本题是一个最长上升子序列的变形,题目给你n种长方体,每种都是无数个,然后让你堆出最大的高度,如果长方体A能放在长方体B上面,那么必须满足长方体A的底面长宽分别都是严格小于长方体B的,根据这一点,给定一块长方体,按照不同的放法,可以生成6个长方体,注意不是3块。另外比较重要的一点就是,这个问题dp前必须要排序,假设长方体的长宽高设为x,y,z,因为前面已经扩展出6个长方体,我就把z当做高,把x,y当做底面,可以考虑下,这样做法确实包括了所有的情况。那么问题来了,我如何排序?假如我不排序,我直接按照dp[i]=max(dp[j])+cub[i].z,(j<i,且满足可以放上去的条件),最后的结果和最长上升子序列一样,max(dp[i]),这样的方程去做,结果会对吗?显然不对。
个人觉得排序可以这样去考虑,排序的目的不是保证后面的每块都能放到它前面任意块的上面,而是保证,后面的每块”有可能“放在它前面任意块的上面,所以有这样的三级排序,优先级先从x,y,z递减,这样能把所有的可能性包含下来,因为这样的排序,不存在这样的情况 ,对于第i个方块,存在第j个长宽都小于它的方块,把j放在了i的前面。可以思考一个问题,假如我排序的优先级是,y,x,z或者z,x,y,这样排序后进行以z为高的dp,结果还会正确吗?
附代码,cub代码中的用p表示了已经。
#include<stdio.h> #include<iostream> #include<algorithm> using namespace std; struct node { int x,y,z; }p[201]; int dp[210]; bool cmp(node a,node b) { if(a.x==b.x) { if(a.y==b.y) return a.z>b.z; return a.y>b.y; } return a.x>b.x; } int main() { int ca=0; int n; while(scanf("%d",&n),n) { int i,j; int nn=0; for(i=1;i<=n;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); p[++nn].x=a;p[nn].y=b;p[nn].z=c; p[++nn].x=b;p[nn].y=a;p[nn].z=c; p[++nn].x=c;p[nn].y=b;p[nn].z=a; p[++nn].x=c;p[nn].y=a;p[nn].z=b; p[++nn].x=b;p[nn].y=c;p[nn].z=a; p[++nn].x=a;p[nn].y=c;p[nn].z=b; } sort(p+1,p+nn+1,cmp); dp[1]=p[1].z; int ans=0; for(i=2;i<=nn;i++) { int max=-1; int flag=0; for(j=i-1;j>=1;j--) { if(p[j].x>p[i].x&&p[j].y>p[i].y) { flag=1; if(max<dp[j]) max=dp[j]; } } if (flag==0) dp[i]=p[i].z; else dp[i]=max+p[i].z; if(ans<dp[i]) ans=dp[i]; } printf("Case %d: maximum height = %d\n",++ca,ans); } return 0 ; }