poj 1020
大致题意也就是给出大正方形和多个小正方形的边长,用多个小正方形能否拼成一个大正方形。
这是一道搜索的题目,如果暴搜的话,边长为23左右就出不来结果过了。看了大牛的思想有很多方法可以剪枝的。
1、 小蛋糕用一个cake[11]的数组来存,cake[i]表示边长为i的蛋糕有cake[i]个,这样可以避免相同的蛋糕多次判断;
2、 用一维的col[41]来代替二维数组,col[i]表示第i行已经用了前col[i]列;
3、 遇到合适情况直接返回,不必要再往下搜索了;
4、 所有的小蛋糕面积和等于大蛋糕面积;
接下来说怎么搜索吧;
1、在col[]数组中找出使用的最小的行minRow,同时也就找出了下一次方小蛋糕的左上顶点;
2、然后在cake[]数组中找可以放置的蛋糕,“可以放置”是一个重要的条件判断;
(1)minRow+i-1<=size(i表示边长为i的蛋糕,size表示大蛋糕的边长)
(2)col[minRow]+i<=size
(3)col[j]+i<=size (minRow<=j<minRow+i-1)
找不到可以放置的直接返回false;
3、放置成功后,重复1,直到放置完毕。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int col[41],cake[11],size,number;
int GetMinRow()
{
int i,minRow,min=41;
for(i=1;i<=size;i++)
if(col[i]<min)
{
min=col[i];
minRow=i;
}
return minRow;
}
int dfs(int curNum)
{
int j,i,minRow;
bool ok=false;
if(curNum==number) return 1;
minRow=GetMinRow();
for(j=10;j>0;j--)
{
ok=false;
if(cake[j] && minRow+j-1<=size && col[minRow]+j<=size)
{
for(i=minRow;i<minRow+j;i++)
{
if(col[i]>col[minRow]) break;
}
if(i==minRow+j) ok=true;
}
if(ok)
{
cake[j]--;
for(i=minRow;i<minRow+j;i++)
{
col[i]+=j;
}
if(dfs(curNum+1)) return 1;
for(i=minRow;i<minRow+j;i++)
{
col[i]-=j;
}
cake[j]++;
}
}
return 0;
}
int main()
{
int i,n,sum,c;
scanf("%d",&n);
while(n--)
{
memset(cake,0,sizeof(cake));
scanf("%d%d",&size,&number);
for(sum=0,i=0;i<number;i++)
{
scanf("%d",&c);
cake[c]++;
sum+=c*c;
}
if(sum!=size*size)
{
printf("HUTUTU!\n");
continue;
}
memset(col,0,sizeof(col));
if(dfs(0)==0)
printf("HUTUTU!\n");
else
printf("KHOOOOB!\n");
}
return 0;
}
浙公网安备 33010602011771号