ACM: 搜索题 poj 1020

Anniversary Cake
 
Description
Nahid Khaleh decides to invite the kids of the "Shahr-e Ghashang" to her wedding anniversary. She wants to prepare a square-shaped chocolate cake with known size. She asks each invited person to determine the size of the piece of cake that he/she wants (which should also be square-shaped). She knows that Mr. Kavoosi would not bear any wasting of the cake. She wants to know whether she can make a square cake with that size that serves everybody exactly with the requested size, and without any waste.

Input

The first line of the input file contains a single integer t (1 ≤ t ≤ 10), the number of test cases, followed by input data for each test case. Each test case consist of a single line containing an integer s, the side of the cake, followed by an integer n (1 ≤ n ≤ 16), the number of cake pieces, followed by n integers (in the range 1..10) specifying the side of each piece.

Output

There should be one output line per test case containing one of the words KHOOOOB! or HUTUTU! depending on whether the cake can be cut into pieces of specified size without any waste or not.

Sample Input

2
4 8 1 1 1 1 1 3 1 1
5 6 3 3 2 1 1 1

Sample Output

KHOOOOB!
HUTUTU!

 

题意: 给出num个小正方形, 问能否拼成n*n大小的大正方形.

 

解题思路:

     1. 一开始我想到是动态规划-状态压缩, 但是很快打消念头, 因为每个小正方形大小可能不一.

        无法子问题重叠, 不符合动态规划条件.(我没想出来怎么DP)

     2. 搜索, 范围最大16个小正方形, 大小1<=size<=10, 16*10*10 = 40*40, 范围搜索还是可以.

        设: a[i]表示size = i的正方形的个数;

            g[i]表示第i行用了前g[i]列(这样可以节省空间 和方便搜索)

     3. 搜索策略:

        (1). 大的正方形比较难处理, 小的正方形比较容易, 先从大的开始.

        (2). 每次都从最左上角开始找出可以放置的位置.

     4. 最后要记住小正方形面积当然要等于大正方形才可以拼成.

 

代码:

#include
#include
#include
using namespace std;
#define MAX 41
#define MAXSIZE 11

int n, num;
int a[MAXSIZE], g[MAX]; //sqrt(16*10*10) = 40
int sum;

int getMin()
{
 int minR, size = MAX;
 for(int i = 1; i <= n; ++i)
 {
  if( g[i] < size )
  {
   size = g[i];
   minR = i;
  }
 }
 return minR;
}

bool dfs(int cur)
{
 int i, j, minR;
 bool flag;
 if( cur == num ) return true;

 minR = getMin(); //找出最左上角的位置
 for(i = MAXSIZE; i >= 1; --i)
 {
  flag = false;
  if( a[i] != 0 && minR+i-1 <= n && g[minR]+i <= n ) //范围和个数
  {
   for(j = minR; j < minR+i; ++j) //判断是否可以放置这个正方形.
    if( g[j] > g[minR] ) break;
   if( j == minR+i ) flag = true; //标记可以放置
  }

  if( flag )
  {
   a[i]--;
   for(j = minR; j < minR+i; ++j)
    g[j] += i; //记录已经放置后状态
   if( dfs(cur+1) ) return true;
   for(j = minR; j < minR+i; ++j)
    g[j] -= i;
   a[i]++;
  }
 }
 return false;
}

int main()
{
// freopen("input.txt", "r", stdin);
 int caseNum;
 scanf("%d", &caseNum);
 while(caseNum--)
 {
  memset(a, 0, sizeof(a));
  memset(g, 0, sizeof(g));
  scanf("%d %d", &n, &num);

  int temp;
  sum = 0;
  for(int i = 0; i < num; ++i)
  {
   scanf("%d", &temp);
   a[temp]++;
   sum += temp*temp;
  }

  if( sum != n*n ) //面积不一样当然拼不成
   printf("HUTUTU!\n");
  else
  {
   if( dfs(0) == true )
    printf("KHOOOOB!\n");
   else
    printf("HUTUTU!\n");
  }
 }
 return 0;
}

你可能感兴趣的:(ACM)