poj1020
dfs
题意:给定一个大正方形的边长,和若干个小正方形的边长,问大的能否由小的拼成。
分析:我们从上到下,从左到右地拼,也就是没列在任意时刻都是上面一段连续的空间被占用,用len[i]记录第i列被占用了几格。用cnt[i]记录边长为i的正方形有几个,枚举要拼的正方形的时候枚举i,这样可以保证当一个正方形匹配失败时,相同的正方形不会被反复尝试。每次选择一个正方形拼到最靠上端的空间中,如果任何正方形都没法拼,则说明那块空间永远无法被占用,所以应该回溯。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define maxl 11
#define maxn 17
int cnt[maxl];
int side, n, area;
int len[maxl * maxn];
bool chk(int used)
{
if (used == n)
return true;
int minl = 110, p = -1;
for (int i = 0; i < side; i++)
if (minl > len[i])
{
minl = len[i];
p = i;
}
for (int i = 0; i < maxl; i++)
if (cnt[i] && len[p] + i <= side && p + i <= side)
{
bool ok = true;
for (int j = p; j < p + i; j++)
if (len[j] != len[p])
{
ok = false;
break;
}
if (ok)
{
cnt[i]--;
for (int j = p; j < p + i; j++)
len[j] += i;
if (chk(used + 1))
return true;
for (int j = p; j < p + i; j++)
len[j] -= i;
cnt[i]++;
}
}
return false;
}
int main()
{
//freopen("t.txt", "r", stdin);
int t;
scanf("%d", &t);
while (t--)
{
memset(len, 0, sizeof(len));
memset(cnt, 0, sizeof(cnt));
scanf("%d%d", &side, &n);
area = 0;
for (int i = 0; i < n; i++)
{
int a;
scanf("%d", &a);
cnt[a]++;
area += a * a;
}
if (area == side * side && chk(0))
printf("KHOOOOB!\n");
else
printf("HUTUTU!\n");
}
return 0;
}