题意:给出正方形蛋糕的边长,然后给出一些小蛋糕的边长(正方形),看这些小的正方形能不能拼成这个大的蛋糕.
思路:感觉就是个二维的 1011..但是写起来还是悲剧啊...最后还是看了解题报告... 这种搜索的技巧,还真难掌握... 具体注释,看代码
#include<iostream>
using namespace std;
//从上到下从左到右 搜索
int cnt[20],len[50];//cnt[i]代表的边长是i的正方形的个数,
//len[i]代表了当前的i列,所占的行的长度
int cake_side,nside;//蛋糕的边长,切成的个数
bool dfs(int used)
{
if(used==nside) return true;
int min=100,k=-1,i,j;
for(i=0;i<cake_side;i++)
if(len[i]<min)
{
min=len[i];
k=i;
}
for(i=1;i<=10;i++)
{
if(cnt[i]!=0&&len[k]+i<=cake_side&&k+i<=cake_side)
{
int wid=0;//用来统计当前最小覆盖的行有多少列,相同的列往后数(根据要添入的正方形边长决定),看有多少连续。
for(j=k;j < cake_side; j++)
{
if(len[j]==len[k]) wid++;
else break;
}
// printf("wid=%d,k=%d\n",wid,k);
if(wid>=i)
{
cnt[i]--;
for(j=k; j < k+i; j++)
len[j]+=i;
if(dfs(used+1))
return true;
for(j=k; j < k+i; j++)
len[j]-=i;
cnt[i]++;
}
}
}
return false;
}
int main()
{
int N,sum,side;
scanf("%d",&N);
while(N--)
{
scanf("%d",&cake_side);
scanf("%d",&nside);
sum=0;
memset(len,0,sizeof(len));
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=nside;i++)
{
scanf("%d",&side);
cnt[side]++;
sum+=(side*side);
}
//cout<<"SUM="<<sum<<endl;
if(sum==cake_side*cake_side&&dfs(0))
printf("KHOOOOB!\n");
else
printf("HUTUTU!\n");
}
}