最近准备进入动态规划的章节,仔细看了看紫书上对01背包的讲解,感觉很好。。之前看《挑战程序设计竞赛》那本书,就没有讲的那么深刻 。 更加深刻的理解了什么叫记录结果再利用,手工操作了一遍01背包的过程,也有点明白它的状态是如何转移的了,而且那个状态方程所构成的递推关系真的很巧妙 。
言归正传。。这道题就是嵌套矩形问题稍微改了一下,之前的嵌套矩形只需要维护一个状态量就行了,但是这道题是立方体,可以翻转的,所以还要维护一个特征量--高。
由于矩形的嵌套关系,每个状态只会出现一次,所以这么表示是完全可以的(和完全背包不同) 。
细节见代码:
#include<bits/stdc++.h> using namespace std; int n,d[35][10],Case = 0; struct node{ int v[5]; }a[35]; int dp(int i,int k) { int& ans = d[i][k]; if(ans!=-1) return ans; ans = 0; for(int j=1;j<=n;j++) { if(k==0) { //不要被吓到。。这三部分只有很小的不同,复制就行了 if((a[j].v[0]>a[i].v[1]&&a[j].v[1]>a[i].v[2])||(a[j].v[1]>a[i].v[1]&&a[j].v[0]>a[i].v[2])) ans = max(ans,dp(j,2)+a[j].v[2]); if((a[j].v[0]>a[i].v[1]&&a[j].v[2]>a[i].v[2])||(a[j].v[2]>a[i].v[1]&&a[j].v[0]>a[i].v[2])) ans = max(ans,dp(j,1)+a[j].v[1]); if((a[j].v[1]>a[i].v[1]&&a[j].v[2]>a[i].v[2])||(a[j].v[2]>a[i].v[1]&&a[j].v[1]>a[i].v[2])) ans = max(ans,dp(j,0)+a[j].v[0]); } else if(k==1) { if((a[j].v[0]>a[i].v[0]&&a[j].v[1]>a[i].v[2])||(a[j].v[1]>a[i].v[0]&&a[j].v[0]>a[i].v[2])) ans = max(ans,dp(j,2)+a[j].v[2]); if((a[j].v[0]>a[i].v[0]&&a[j].v[2]>a[i].v[2])||(a[j].v[2]>a[i].v[0]&&a[j].v[0]>a[i].v[2])) ans = max(ans,dp(j,1)+a[j].v[1]); if((a[j].v[1]>a[i].v[0]&&a[j].v[2]>a[i].v[2])||(a[j].v[2]>a[i].v[0]&&a[j].v[1]>a[i].v[2])) ans = max(ans,dp(j,0)+a[j].v[0]); } else { if((a[j].v[0]>a[i].v[0]&&a[j].v[1]>a[i].v[1])||(a[j].v[1]>a[i].v[0]&&a[j].v[0]>a[i].v[1])) ans = max(ans,dp(j,2)+a[j].v[2]); if((a[j].v[0]>a[i].v[0]&&a[j].v[2]>a[i].v[1])||(a[j].v[2]>a[i].v[0]&&a[j].v[0]>a[i].v[1])) ans = max(ans,dp(j,1)+a[j].v[1]); if((a[j].v[1]>a[i].v[0]&&a[j].v[2]>a[i].v[1])||(a[j].v[2]>a[i].v[0]&&a[j].v[1]>a[i].v[1])) ans = max(ans,dp(j,0)+a[j].v[0]); } } return ans; } int main() { while(~scanf("%d",&n)&&n) { for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i].v[0],&a[i].v[1],&a[i].v[2]); int ans = -1; for(int i=1;i<=n;i++) { for(int j=0;j<=2;j++) { memset(d,-1,sizeof(d));//每次都要清空,因为每一次的起点不同,导致结果大不一样 ans = max(ans,dp(i,j)+a[i].v[j]); } } printf("Case %d: maximum height = %d\n",++Case,ans); } return 0; }