本题是一个最长上升子序列的变形,题目给你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 ;
}