11H:迷宫入口
- 总时间限制:
- 1000ms
- 内存限制:
- 10000kB
- 描述
-
爱好探险的你,找到一座装满了宝藏的迷宫的入口,你看到入口的大门上有一个边长为s的正方形的大锁,旁边散落着n块正方形的金属小片,你意识到锁的钥匙,即是用这n小块,拼成大门上的正方形,你想知道是否能拼成这把钥匙打开迷宫的大门。
- 输入
- 输入包含多组数组,第一行是一个整数t(1 <= t <= 10),表示有t组数据。接下里每组数组包含整数s,即锁的边长,整数n(1 <= n <= 16),即金属小片的数量,接下来n个整数,分别是各个小片的边长ci(1 <= ci <= 10)。
- 输出
- 每组数据输出一行,输出“YES"或者"NO",表示是否可以打开大门。
- 样例输入
-
2 4 8 1 1 1 1 1 3 1 1 5 6 3 3 2 1 1 1
- 样例输出
-
YES NO
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 int a[15]; 7 int c[17]; 8 int m[45][45]; 9 int s, n; 10 void fill(int x, int y, int L, int vol){ //以(x,y)左上角填充内容为vol的正方形 11 for(int i = x; i < x+L; i++) 12 for(int j = y; j < y+L; j++) 13 m[i][j] = vol; 14 } 15 bool dfs(int x,int y){ 16 if(m[x][y]){ 17 if(y==s-1){ 18 if(x==s-1)return 1; 19 else return dfs(x+1,0); 20 } 21 else return dfs(x,y+1); 22 } 23 bool ret=0; 24 for(int L=1;!ret;L++){ 25 if(y+L>s||x+L>s||m[x][y+L-1])break; 26 if(!c[L])continue; 27 c[L]--; 28 fill(x,y,L,1); 29 ret|=dfs(x,y); 30 fill(x,y,L,0); 31 c[L]++; 32 } 33 return ret; 34 } 35 36 int main(){ 37 int t; 38 cin>>t; 39 while(t--){ 40 cin>>s>>n; 41 memset(a, 0, sizeof(a)); 42 memset(c, 0, sizeof(c)); 43 memset(m, 0, sizeof(m)); 44 for(int i = 1; i <= n; i++){ 45 cin>>a[i]; 46 c[a[i]] ++; 47 } 48 if(s>40){ 49 cout<<"NO"<<endl; 50 return 0; 51 } 52 bool ans = dfs(0, 0); 53 if(ans) cout<<"YES"<<endl; 54 else cout<<"NO"<<endl; 55 } 56 return 0; 57 }
备注:这差不多也就是标答,这么暴力居然也可以过orz 另外我怀疑这道题数据范围写错了,因为l和c数组开到40+才能过。开小了就是WA问了助教,等待答复中。。
大于四十不可能是因为,16个片,每个边长最大为10(这么看数据范围又没错?),加在一起面积也就是1600,也就是说锁的边长大于40就不可能凑出来了。当然不写这个也可以AC。
然后这个dfs的写法就 非常神奇……从左上角开始填充,先填充到最右,然后换行。标黄的地方我还是没太明白,wsl。我明白了。
因为前面说的填充顺序的问题,这时候填完了第一行的正方形,该填第二行了。这时候边长是从小往大尝试的,这很重要,所以x+L或者y+L出界了肯定不行要break这是显然的;还有就是如果像途中虚线正方形一样,如果它右上角已经开始侵占了第一行的正方形的位置(之前填充过)也说明边长太大了,要break。
为啥这么难。
这个dfs也可以不这么写,用更常规的方法是这样的:
1 #include <iostream> 2 #include <vector> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 int a[45]; 7 int c[45]; 8 int m[45][45]; 9 int s, n; 10 void fill(int x, int y, int L, int vol){ //以(x,y)左上角填充内容为vol的正方形 11 for(int i = x; i < x+L; i++) 12 for(int j = y; j < y+L; j++) 13 m[i][j] = vol; 14 } 15 bool dfs(int x,int y){ 16 if(m[x][y]){ 17 if(y==s-1){ 18 if(x==s-1)return 1; 19 else return dfs(x+1,0); 20 } 21 else return dfs(x,y+1); 22 } 23 //bool ret=0; 24 for(int L=1;;L++){ 25 if(y+L>s||x+L>s||m[x][y+L-1])break; 26 if(!c[L])continue; 27 c[L]--; 28 fill(x,y,L,1); 29 if(dfs(x,y)) return true; 30 // ret|=dfs(x,y); 31 fill(x,y,L,0); 32 c[L]++; 33 } 34 return false; 35 } 36 37 int main(){ 38 int t; 39 cin>>t; 40 while(t--){ 41 cin>>s>>n; 42 memset(a, 0, sizeof(a)); 43 memset(c, 0, sizeof(c)); 44 memset(m, 0, sizeof(m)); 45 for(int i = 1; i <= n; i++){ 46 cin>>a[i]; 47 c[a[i]] ++; 48 } 49 if(s>40){ 50 cout<<"NO"<<endl; 51 return 0; 52 } 53 bool ans = dfs(0, 0); 54 if(ans) cout<<"YES"<<endl; 55 else cout<<"NO"<<endl; 56 } 57 return 0; 58 }