题目描述:有一个边长为size的正方形蛋糕,现在问这块蛋糕是否恰好能被分成n块特定边长的正方形小蛋糕。
输入格式:第一行一个整数s,表示有s组数据,每组数据一行,每行开头一个整数s,表示大蛋糕的边长,然后是一个整数n,表示小蛋糕的数量,接下来n个整数,代表这个n块小蛋糕的边长。
输出格式:每组数据输出一行,”KHOOOOB!”或者”HUTUTU!”,分别代表恰好可以分和不能分。
数据约定:1<=n<=16, 小蛋糕的边长不大于10
解题思路:搜索!!反过来想,把分割大正方形看成往大正方形里放小正方形。
抓住核心思想:只要任何一个小正方形无法被放进去,则该组数据一定无解!所以,可以贪心!
#include <cstdio>
bool search(int deep, int target, int size, int *cake);
int main(int argc, char const *argv[])
{
int t;
scanf("%d", &t);
while(t--){
int size, n, cake[40]={0}, tot=0, piecesize;
scanf("%d%d", &size, &n);
for(int i=0; i<n; ++i){
scanf("%d", &piecesize);
tot += piecesize*piecesize;
++cake[piecesize];
}
bool flag=false;
if(tot==size*size) { flag=search(0, n, size, cake); }
if(flag){ printf("KHOOOOB!\n");}
else { printf("HUTUTU!\n");}
}
return 0;
}
bool search(int finish, int target, int size, int *cake)
{
bool ans=false;
static int row[40]={0};
if(finish==target){ ans=true; }
else{
int pos=40, minrow=1024;
for(int i=0; i<size; ++i) { //找最小的可以放蛋糕的行
if(row[i]<minrow){
minrow=row[i];
pos=i;
}
}
int h=0;
while(pos+h<size&&row[pos+h]==minrow) { ++h; } //最大的可以放蛋糕的列数
int l=size-minrow; //最大的可以放蛋糕的行数
int maxpiece=l<h?l:h; //最大的可以放蛋糕的边长
for(int i=maxpiece; i>0; --i){
if(cake[i]>0){
--cake[i];
for(int j=pos; j<pos+i; ++j) { row[j]+=i; }
ans=search(finish+1,target,size,cake); //深度搜索、回溯
for(int j=pos; j<pos+i; ++j) { row[j]-=i; }
++cake[i];
}
if(ans) { break; }
}
}
return ans;
}