动态规划:巴比伦塔
做了一道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 }