地址:http://poj.org/problem?id=1020
题意:给一块边长为boxsize的正方形大蛋糕,要求分为n块不同规格的正方形小蛋糕,问是否可行。
解法:
1.将大蛋糕看成一个盒子,就是在一个boxsize边长的盒子里面放n个小正方形蛋糕。
2.注意剪枝,小蛋糕面积和与蛋糕盒面积不符或者有两块小蛋糕的边长都超过boxsize/2那么一定不可行。
3.DFS,思想是从左往右,从下到上的放(从上到下一样),先放大蛋糕,后放小蛋糕,因为小蛋糕的活动性强。
4.注意回溯。
#include<iostream>
#include<cstring>
using namespace std;
int n; //蛋糕块数
int boxsize; //盒子边长
int col[41]; //存储第i列填充快数
int sizenum[11]; //存储i规格的蛋糕块数
bool dfs(int num){ //加入了n块蛋糕
int i,j;
if(num==n) return 1;
//寻找col[]中的最小值
int pos,min;
min=50;
for(i=1;i<=boxsize;i++){
if(min>col[i]){
min=col[i];
pos=i;
}
}
for(i=10;i>0;i--){
if(!sizenum[i]) continue;
if(pos+i-1>boxsize || col[pos]+i>boxsize) continue;
int wide=0;
for(j=pos;j<=pos+i-1;j++){
if(col[j]<=col[pos]){
wide++;
continue;
}
break;
}
if(wide<i) continue;
sizenum[i]--;
for(j=pos;j<pos+i;j++){
col[j]+=i;
}
if(dfs(num+1)) return 1;
sizenum[i]++;
for(j=pos;j<pos+i;j++){
col[j]-=i;
}
}
return 0;
}
int main(){
int i,j,t;
int bnum; //记录蛋糕边长超过盒子边长一般的数目,用于剪枝
int area; //记录蛋糕面积和
int size;
cin>>t;
while(t--){
cin>>boxsize>>n;
area=bnum=0;
memset(col,0,sizeof(col));
memset(sizenum,0,sizeof(sizenum));
for(i=0;i<n;i++){
cin>>size;
sizenum[size]++;
}
for(i=1;i<=10;i++){
area+=i*i*sizenum[i];
if(i>boxsize/2) bnum+=sizenum[i];
if(bnum>1||area>boxsize*boxsize)
break;
}
if(bnum>1||area>boxsize*boxsize){
cout<<"HUTUTU!"<<endl;
continue;
}
bool result=dfs(0);
if(result)
cout<<"KHOOOOB!"<<endl;
else
cout<<"HUTUTU!"<<endl;
}
return 0;
}