这是一道搜索题,搜索的时候有2个剪枝:1、搜索顺序。如果两个正方形的边长相同,则在同一层只搜索一次就可以。2、在每一层搜索时,从每一列中最小的行开始,如果正方形放不下,换个较小的。第一个条件很重要,如果不注意会超时。在存矩形的时候有个优化,只用一个一维数组存,表示这一列已经放了多少行。
这道题自己想了很长时间,还是不会,后来看了别人的思路,觉得自己也曾这样想过,但一直不能不会怎么存就没写下去,现在算是会了,但是不够兴奋,毕竟不是自己做出来的,还要多做题,多涨经验。
看了网上不少的题解,几乎都是这个方法,但交上后最好的也才是32ms,真不知那些0ms是怎么出来的。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int edg, n;
int used[100], v[20];
int dfs(int cur)
{
if(cur == n) return 1;
int row = 100, colum = 0;
for(int i = 1; i <= edg; i++){
if(row > used[i]){
row = used[i];
colum = i;
}
}
for(int i = 10; i > 0; i--){
if(v[i] && row + i <= edg && colum + i - 1 <= edg){
int flag = 0;
for(int j = colum; j < colum + i; j++){
if(used[j] > row){
flag = 1;
break;
}
}
if(!flag){
v[i]--;
for(int j = colum; j < colum + i; j++)
used[j] += i;
if(dfs(cur + 1)) return 1;
v[i]++;
for(int j = colum; j < colum + i; j++)
used[j] -= i;
}
}
}
return 0;
}
int main()
{
//freopen("input.txt", "r", stdin);
int nCase, sum, s;
scanf("%d", &nCase);
while(nCase--){
scanf("%d %d", &edg, &n);
sum = 0;
memset(v, 0, sizeof(v));
for(int i = 0; i < n; i++){
scanf("%d", &s);
v[s]++;
sum += s * s;
}
if(sum != edg * edg){
printf("HUTUTU!\n");
}else{
memset(used, 0, sizeof(used));
if(dfs(0)) printf("KHOOOOB!\n");
else printf("HUTUTU!\n");
}
}
return 0;
}