POJ 1020 Anniversary Cake 回溯DFS

题意:给你一个大的正方形,和一些小的正放形,问你,这些小的正方形能不能填满整个大的正方形,不能有重合。

思路:首先以先选择大的正方形为优,留下的小的正方形的灵活性高,填放正方形的方法是,最作最上开始,先向num[a](每a行已经被用过的1*1的正方形数量)最小的行开始填写,如果连续的num[i]=num[a],那么就可以往上填写边长<=|a-i|+1的小正方形了。就当前来说,对于可以放入的小正方形,我们先把它放在这里,dfs继续,如果成功表示这里的放这个正方形是正确的,如果不可以,那么这个位置就要改变为其它的边长更小的小正方形了。

我看题解看了一上午…………

//属于尝试位置的问题 ,如果这里放了这个,那么它是否可以得到正确的答案 
#include<iostream>
#include<cstdio>
#include<cstring>
#define inf 0x7fffffff
using namespace std;
int Z,n;
int sidenum[20],sum,bignum;
void Input()
{sum=0;bignum=0;scanf("%d %d",&Z,&n);memset(sidenum,0,sizeof(sidenum)); for(int i=1;i<=n;i++){int a;scanf("%d",&a);sidenum[a]++;sum+=a*a;if(a>Z/2) bignum++; }
}
int hang[50];
int getmin()
{int mmin=inf,mark;for(int i=1;i<=Z;i++){if(mmin>hang[i]){mmin=hang[i];mark=i;}}return mark;
}
int dfs(int used)
{int falg=0;if(used==n) return 1;int row=getmin();for(int i=10;i>=1;i--){falg=0;if(sidenum[i]&&row+i-1<=Z&&hang[row]+i<=Z){int mark=1;for(int j=row;j<=row+i-1;j++){if(hang[j]>hang[row]){mark=0;break;}}if(mark) falg=1;}if(falg){sidenum[i]--;for(int j=row;j<=row+i-1;j++){hang[j]+=i;}if(dfs(used+1)) return 1;for(int j=row;j<=row+i-1;j++){hang[j]-=i;}sidenum[i]++;}}return 0;
}
void treatment()
{memset(hang,0,sizeof(hang));if(sum==Z*Z&&bignum<=1) {if(dfs(0)) printf("KHOOOOB!\n");else printf("HUTUTU!\n");}else printf("HUTUTU!\n");
}
int main()
{int t;scanf("%d",&t);while(t--){Input();treatment();}return 0;
}