poj 1020 Anniversary Cake
搜索
题意:先给出大方阵的边长,再给出m个小方阵并给出每个方阵的边长,问是否可以不发生重叠地把小方阵放进大方阵中,并且大方阵完全利用没有剩余
这题的代码不难写,关键是要找到策略,这题的策略比搜索本身的剪枝更有价值
摆放小方阵的策略是,尽可能往上面摆,然后尽可能往左边摆。另外有个策略一开始想错了,我是想先把小方阵排序,先放好大的,再放好小的,这样在摆放过程中可能出问题,画图可知,正确的策略是就目前的摆放情况,能放得到下哪个就放哪个,无所谓大小
为了满足尽可能放在左上方的条件,需要记录大方针的状态
col[i]的意义是,第i列,从最顶部数下来,被连续占据了多少格
注意在整个摆放过程中,每一列都保证是被连续占据的,不会出现断开的情况,这要求在搜索剪枝的时候处理好
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define N 55 #define M 15 int n,m; int col[N],s[M]; bool dfs(int mm) { if(mm >= m) return true; int Min = N , c = 0; for(int i=1; i<=n; i++) if(col[i] < Min) { Min = col[i]; c = i; } for(int i=1; i<=10; i++) if(s[i]) { bool ok = true; if( !(c+i-1 <= n && col[c]+i <= n) ) continue; for(int k = c; k <= c+i-1; k++) if(col[k] != col[c]) { ok = false; break; } if(!ok) continue; s[i]--; for(int k=c; k <= c+i-1; k++) col[k] += i; if(dfs(mm+1)) return true; s[i]++; for(int k=c; k <= c+i-1; k++) col[k] -= i; } return false; } int main() { int cas; cin >> cas; while(cas--) { int x,sum = 0; cin >> n >> m; memset(s,0,sizeof(s)); for(int i=0; i<m; i++) { cin >> x; s[x]++; sum += x * x; } memset(col,0,sizeof(col)); if(sum != n * n || !dfs(0)) cout << "HUTUTU!" << endl; else cout << "KHOOOOB!" << endl; } return 0; }