和The Tower of Babylon一模一样,这里给出两个代码:一个是直接做的,不说了;
另一个是参考了Staginner大牛的方法,做了一个优化:将底面积按大到小排序,这样搜索时,只用从当前石块的下一个石块开始即可,最后打印 f[1] 即可,复杂度降低很明显的。
/* 方法二实际上有个错误,具体见后述。*/
方法一
1 # include <stdio.h>
2 # include <memory.h>
3 # include <stdlib.h>
4
5 typedef struct {
6 int x, y, h;
7 }block;
8
9 int n;
10 int f[92];
11 block a[92];
12
13 int cmp(const void *x, const void *y)
14 {
15 return (*(int *)x<*(int *)y ? -1:1);
16 }
17
18 int dp(int i); /* 记忆化搜索,f[i] = dp(i); f[i]定义为从第i个箱子出发所能到达的最大高度 */
19
20 int main()
21 {
22 int tmp[3], i, maxH, cnt;
23
24 cnt = 0;
25 while (~scanf("%d", &n))
26 {
27 if (!n) break;
28
29 ++cnt;
30 n *= 3;
31 for ( i = 1; i <= n; ++i)
32 {
33 scanf("%d%d%d", &tmp[0], &tmp[1], &tmp[2]);
34 qsort(tmp, 3, sizeof(int), cmp);
35 a[i].x = tmp[0]; a[i].y = tmp[1]; a[i].h = tmp[2]; ++i;
36 a[i].x = tmp[1]; a[i].y = tmp[2]; a[i].h = tmp[0]; ++i;
37 a[i].x = tmp[0]; a[i].y = tmp[2]; a[i].h = tmp[1];
38 }
39
40 memset(f, 0, sizeof(f));
41
42 maxH = 0;
43 for (i = 1; i <= n; ++i)
44 if (maxH < dp(i)) maxH = f[i];
45
46 printf("Case %d: maximum height = %d\n", cnt, maxH);
47 }
48
49 return 0;
50 }
51
52 int dp(int i)
53 {
54 int k, tmp;
55
56 if (f[i]) return f[i];
57 f[i] = a[i].h;
58 for ( k = 1; k <= n; ++k)
59 if (a[k].x < a[i].x && a[k].y < a[i].y && f[i] < (tmp = dp(k)+a[i].h))
60 f[i] = tmp;
61
62 return f[i];
63 }
1 # include <stdio.h>
2 # include <memory.h>
3 # include <stdlib.h>
4
5 typedef struct {
6 int x, y, h;
7 }block;
8
9 int n;
10 int f[92];
11 block a[92];
12
13 int cmp(const void *xx, const void *yy)
14 {
15 return (*(int *)xx<*(int *)yy ? -1:1);
16 }
17
18 int block_cmp(const void *xx, const void *yy)
19 {
20 return (*(block *)xx).x * (*(block *)xx).y > (*(block *)yy).x * (*(block *)yy).y ? -1:1;
21 }
22
23 int dp(int i); /* 记忆化搜索,f[i] = dp(i); f[i]定义为从第i个箱子出发所能到达的最大高度 */
24
25 int main()
26 {
27 int tmp[3], i, cnt;
28
29 cnt = 0;
30 while (~scanf("%d", &n))
31 {
32 if (!n) break;
33
34 ++cnt;
35 n *= 3;
36 for ( i = 1; i <= n; ++i)
37 {
38 scanf("%d%d%d", &tmp[0], &tmp[1], &tmp[2]);
39 qsort(tmp, 3, sizeof(int), cmp);
40 a[i].x = tmp[0]; a[i].y = tmp[1]; a[i].h = tmp[2]; ++i;
41 a[i].x = tmp[1]; a[i].y = tmp[2]; a[i].h = tmp[0]; ++i;
42 a[i].x = tmp[0]; a[i].y = tmp[2]; a[i].h = tmp[1];
43 }
44
45 memset(f, 0, sizeof(f));
46 qsort(a+1, n, sizeof(block), block_cmp);
47
48 printf("Case %d: maximum height = %d\n", cnt, dp(1));
49 }
50
51 return 0;
52 }
53
54 int dp(int i)
55 {
56 int k, tmp;
57
58 if (f[i]) return f[i];
59 f[i] = a[i].h;
60 for ( k = i+1; k <= n; ++k)
61 if (a[k].x < a[i].x && a[k].y < a[i].y && f[i] < (tmp = dp(k)+a[i].h))
62 f[i] = tmp;
63
64 return f[i];
65 }
为什么是按面积大小呢?因为会出现a[i].x>b[j].x && a[i].y<a[j].y的情况,如果按照能否放上去的方式排序,这种情况将处于无序状态;
ZOJ这道题的测试数据看来是弱的,因为实际上即使做了上述的优化,最终还必须循环查找f[i]的最大值,可以举个例子:第一个是一个6*6的正方形,第二个是3*11的长方形,后面的都可以放在这个长方形上(或者给三组数据,第三组为2*10),那么最终f[2]显然是最大的,所以方法二对应的代码48行那里还必须循环查找最大值,但是判的结果是AC, 0MS。。