POJ1020 Anniversary Cake

题目来源:http://poj.org/problem?id=1020

题目大意:有一块边长为s的正方形大蛋糕,有n个客人,每个客人想分一块边长为si的正方形蛋糕。求这块大蛋糕能否恰好满足所有客人的需求而不浪费。

输入:第一行为测试用例数。接下来每行的第一个数位大蛋糕的边长,第二个数位客人的数目n,接下来的n个数为每个客人想要的蛋糕的边长。

输出:若能恰好分完输出“KHOOOOB!”,否则输出“HUTUTU!


 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!

一开始用贪心方法做,即从大块的开始切,总是选最靠近左下角的位置开始切。大多数用例都可以通过,直到遇到这组数据:

10 14 1 1 1 1 1 4 4 3 3 3 3 3 3 3 

发现贪心是有问题的。

后来看了牛人的思路,用DFS解决。

切蛋糕时总是自下而上,自左而右。优先切大蛋糕。

解决方案精彩的地方不在于DFS本身,而在于每切一次蛋糕,标记所有蛋糕位置的方法。标记每个格子的状态再查找会TLE。牛人想到的方法是把蛋糕“按列标记”。建立一维数组,d[s],s为大蛋糕边长,d[i]记录每列第一个为空的格子的行号。

 1 //////////////////////////////////////////////////////////////////////////
 2 //        POJ1020 Anniversary Cake
 3 //        Memory: 268K        Time: 485MS
 4 //        Language: C++        Result: Accepted
 5 //////////////////////////////////////////////////////////////////////////
 6 #include <iostream>
 7 using namespace std;
 8 
 9 int s, n;
10 int c[11];
11 int d[41];
12 
13 int sum;
14 bool ok;
15 
16 void reset() {
17     memset(c, 0, sizeof(c));
18     for (int i = 0; i < 41; ++i) {
19         d[i] = 1;
20     }
21     sum = 0;
22     ok = false;
23 }
24 
25 void dfs(int a) {
26     if (a == n) {
27         ok = true; 
28         exit;
29     }
30     int i, j;
31     int row, clo;
32     bool f;
33     for (i = 1, clo = 41; i <= s; ++i) {
34         if (d[i] < clo) {
35             clo = d[i];
36             row = i;
37         }
38     }
39     for (i = 10; i > 0; --i) {
40         if (c[i] > 0 && row + i - 1 <= s && clo + i - 1 <= s) {
41             for (j = row, f = true; j <= row + i - 1; ++j) {
42                 if (d[j] > clo) {
43                     f = false; 
44                     break;
45                 }
46             }
47             if (f) {
48                 for (j = row; j <= row + i - 1; ++j) {
49                     d[j] += i;
50                 }
51                 --c[i];
52                 dfs(a + 1);
53                 ++c[i];
54                 for (j = row; j <= row + i - 1; ++j) {
55                     d[j] -= i;
56                 }
57             }
58         }
59     }
60 }
61 
62 int main(void) {
63     int nCase;
64     cin >> nCase;
65     for (int caseNo = 1; caseNo <= nCase; ++caseNo) {
66         reset();
67         cin >> s >> n;
68         for (int i = 1; i <= n; ++i) {
69             int t ;
70             cin >> t;
71             ++c[t];
72             sum += t * t;
73         }
74         if (sum != s * s) {
75             cout << "HUTUTU!" << endl;
76             continue;
77         }
78         dfs(0);
79         if (ok) {
80             cout << "KHOOOOB!" <<endl;
81         }
82         else {
83             cout << "HUTUTU!" << endl;
84         }
85     }
86     system("pause");
87     return 0;
88 }
View Code
posted @ 2013-07-31 16:37  小菜刷题史  阅读(299)  评论(0编辑  收藏  举报