poj1020

dfs

题意:给定一个大正方形的边长,和若干个小正方形的边长,问大的能否由小的拼成。

分析:我们从上到下,从左到右地拼,也就是没列在任意时刻都是上面一段连续的空间被占用,用len[i]记录第i列被占用了几格。用cnt[i]记录边长为i的正方形有几个,枚举要拼的正方形的时候枚举i,这样可以保证当一个正方形匹配失败时,相同的正方形不会被反复尝试。每次选择一个正方形拼到最靠上端的空间中,如果任何正方形都没法拼,则说明那块空间永远无法被占用,所以应该回溯。

View Code
#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;
}

posted @ 2011-07-21 15:46  金海峰  阅读(920)  评论(2编辑  收藏  举报