参考自:http://exp-blog.com
解题思路:
把大蛋糕想象为一个蛋糕盒子,往里面装小蛋糕。
装蛋糕时遵循以下原则:
1.自下而上,自左至右:即先装盒子底部,再继续往上装,且每一层都靠左放蛋糕;
2.大蛋糕优先装,因为小蛋糕灵活度比较高。
dfs:
每放入一个蛋糕,怎样标记盒子已经放有蛋糕的位置:
把盒子看做多个1x1格子,也把小蛋糕看做多个1x1的单位,建立一维数组col[ BoxSize ],每放入一个蛋糕,就记录每列的格子被填充的数目。
补充:
大蛋糕最大也就40x40:10x10x16=1600,1600开方等于40
//dfs
#include <iostream>
#include <cstring>
using namespace std;
int BoxSize;//盒子尺寸
int n;//蛋糕总数
int SizeNum[11];//各种尺寸的蛋糕个数
//把盒子分割成BoxSize*BoxSize个1*1大小的小格子
int col[41];//col[i]记录第i列被填充了的格子数
bool DFS(int FillNum) {//FillNum:已放入盒子的蛋糕数
if (FillNum == n)//递归出口
return true;
//寻找格子数被填充最少的列,靠左优先
int min = 50;
int prow;
for (int i = 1; i <= BoxSize; i++) {
if (min > col[i]) {
min = col[i];
prow = i;
}
}
//枚举蛋糕,从大到小、自下而上地放入盒子
for (int len = 10; len >= 1; len--) {
if (!SizeNum[len])
continue;
//检查尺寸为len的蛋糕,放入盒子时在纵向和横向是否越界
if (BoxSize - col[prow] >= len && BoxSize - prow + 1 >= len) {
//检查盒子从第prow列到第prow+len-1列,共len列的宽度wide中
//是否每列剩余的空间都足够放入高度为len的蛋糕
int wide = 0;
for (int r = prow; r <= prow + len - 1; r++) {
if (col[r] <= col[prow]) {//比较各列的"填充数"
wide++;
continue;
}
break;
}
if (wide >= len) {
int r;
SizeNum[len]--;//放入尺寸为len的蛋糕
for (r = prow; r <= prow + len - 1; r++)
col[r] += len;
if (DFS(FillNum + 1))//递归,放下一个蛋糕
return true;
//回溯
SizeNum[len]++;
for (r = prow; r <= prow + len - 1; r++)
col[r] -= len;
}
}
}
return false;
}
int main() {
int test;
cin >> test;
while (test--) {
memset(SizeNum, 0, sizeof(SizeNum));
memset(col, 0, sizeof(col));
cin >> BoxSize >> n;
int cnt = 0; //记录size>(BoxSize/2)的蛋糕个数
int area = 0;//所有蛋糕的面积之和
for (int i = 1; i <= n; i++) {
int len;
cin >> len;
area += len * len;
SizeNum[len]++;
if (len > BoxSize / 2)
cnt++;
}
if (cnt > 1 || area != BoxSize * BoxSize) {
cout << "HUTUTU!" << endl;
continue;
}
if(DFS(0))
cout << "KHOOOOB!" << endl;
else
cout << "HUTUTU!" << endl;
}
return 0;
}