动态规划:巴比伦塔

  做了一道ZOJ上的题目,发现是一道经典原题的改编(只改了题目背景。。数据都一样)。

  ZOJ Problem Set - 1093 解题报告

  原题地址:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1093

  题目分类:动态规划

  题目大意:有n种木块,每种都是无限提供,木块可以随意摆放(即每条边都可能为高)。当某一块木块的长和宽都小于下面的木块时,才能叠在上面。要求最高能叠多高。

  恰好在做这一题的时候,看了看书,发现了一道例题跟这题一模一样——巴比伦塔。所以我把题目原型摆出来。

  巴比伦塔(The Tower of Babylon,UVa 437)http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=19214

    有n(n≤30)种立方体,每种有无穷多个。要求选一些立方体摞成一根尽量高的柱子(可以自行选择哪一条边作为高),使得每个立方体的底面长宽分别严格小于它下方立方体的底面长宽。

  每个人有每个人的写法,或许有比我的代码更简洁的,不过我只讲我的思路,我觉得简单易懂的。

  每一种木块都有三种摆放方式,因为有三条边。用b[n][3]来储存输入的每个木块的长宽高,再用a[n*3][3]储存所有的情况。刚开始我想先排序然后判断可以叠加就一直往上加,然后发现答案是错的。这样是贪心,但不能用贪心,因为每选一种木块都会影响到后面的所有木块。我们要分析问题的状态。在这3*n种情况中,我们用d[i]来表示以第 i 块木块为顶层的最大高度。因为能放在第 i 块木块下方的情况可能不止一种,当然也可能没有,所以我又用了一个put[i][j]表示第 i 块木块能否放在第 j 块木块上。于是 d[i] = max{a[i],d[j]+a[i] | 0<=j<3*n,put[i][j] = 1} 。这样就得到了状态转移方程。其实每次做动态规划的关键就是几点:1、状态和状态转移方程。2、做记录。 做记录就是我们这里的d[i],这样每个方案只会计算一次,不会重复计算,这才体现了动态规划的优点。最终我的所求的最大高度 maxheight = max {d[i] | 0<=i<3*n}。

  把样例测试过了之后就一遍AC了。代码如下:http://paste.ubuntu.com/15332896/

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstring>
 4 using namespace std;
 5 
 6 int a[91][3];        //所有木块可能
 7 int put[91][91];    //put[i][j]表示i能放在j上
 8 int d[91];            //d[i]表示以第i个木块为顶层的最大高度
 9 int n;
10 int dp(int i)        //以第i块木板为顶的最大高度
11 {
12     int j;
13     int &ans = d[i];
14     if(ans > 0)    return ans;
15     ans = a[i][2];
16     for(j=0;j<3*n;j++)
17     {
18         if(put[i][j])
19         {
20             ans = max(ans,dp(j) + a[i][2]);
21         }
22     }
23     return ans;
24 }
25 void output(int times)
26 {
27     int i,j,height = 0,h = 0;
28     for(i=0;i<3*n;i++)
29     {
30         for(j=0;j<3*n;j++)
31         {
32             if((a[i][0] < a[j][0] && a[i][1] < a[j][1]) || (a[i][0] < a[j][1] && a[i][1] < a[j][0]))
33             {
34                 put[i][j] = 1;
35             }
36         }
37     }
38     for(i=0;i<3*n;i++)
39     {
40         h = dp(i);
41         height = max(h,height);
42     }
43     cout<<"Case "<<times<<": maximum height = "<<height<<endl;
44 }
45 int main()
46 {
47     int block[33][3];
48     int i,c,time = 1;
49     while(cin>>n && n)
50     {
51         c = -1;
52         for(i=0;i<n;i++)
53         {
54             cin>>block[i][0]>>block[i][1]>>block[i][2];
55             a[++c][0] = block[i][0];
56             a[c][1] = block[i][1];
57             a[c][2] = block[i][2];
58             a[++c][0] = block[i][0];
59             a[c][1] = block[i][2];
60             a[c][2] = block[i][1];
61             a[++c][0] = block[i][1];
62             a[c][1] = block[i][2];
63             a[c][2] = block[i][0];
64         }
65         //cout<<"可能情况:"<<endl;
66         //for(i=0;i<3*n;i++)
67         //    cout<<"i="<<i<<": "<<a[i][0]<<" "<<a[i][1]<<" "<<a[i][2]<<endl;
68         memset(d,0,sizeof(d));
69         memset(put,0,sizeof(put));
70         output(time);
71         time++;
72     }
73 }

 

posted on 2016-03-09 12:51  Alinshans  阅读(821)  评论(0编辑  收藏  举报