题意:就是用几个小正方形,去拼成个大的正方形。
思路:从大到小,从左到右,深搜,不是很难,
网上的代码很简洁,我就不用自己的了,加点注释吧
#include <stdio.h>
#include <memory.h>
int cnt[20]; //记录长度为i的正方形个数
int len[50]; //记录目前第i列覆盖长度
int cake_side, npiece;
bool chk(int used)
{
if(used == npiece) //所有正方形都用上了,返回真,跳出
return true;
int min = 100, ind = -1;
for(int i = 0; i < cake_side; i++) //枚举大蛋糕边的长度
if(min > len[i])
{
min = len[i]; /* 找目前覆盖最小的那一列 */
ind = i; //标记标号
}
//先放大的后放小的
for(int i = 1; i <= 10; i++)
if(cnt[i] && len[ind] + i <= cake_side) //有i这个边长,加上刚才最小的覆盖,合起来的值小于等于大正方形的边长
{
int wid = 0;/* 放置宽为 i 的 */
for(int j = ind; j < cake_side; j++) //检测宽度是否符合要求,即是否放得下边长为i的正方形
if(len[j] == len[ind]) wid++;
else break;
if(wid >= i) //能放下
{
cnt[i]--; //在下一层递归中,i用掉了一个
for(int j = ind; j < ind + i; j++) //从ind到i+ind列覆盖的值更新,进入下一层递归
len[j] += i;
if(chk(used + 1)) //used表示用的正方形数
return true;
for(int j = ind; j < ind + i; j++) //更新值变回来,继续循环,不影响下次枚举
len[j] -= i;
cnt[i]++; //同上
}
}
return false;
}
int main()
{
int cs = 0;
scanf("%d", &cs);
while(cs--)
{
memset(len, 0, sizeof(len));
memset(cnt, 0, sizeof(cnt));
int area = 0;
scanf("%d %d", &cake_side, &npiece);
for(int i = 0; i < npiece; i++)
{
int side;
scanf("%d", &side);
cnt[side]++;
area += side * side;
}
if(cake_side * cake_side == area && chk(0))
printf("KHOOOOB!\n");
else
printf("HUTUTU!\n");
}
return 0;
}