本題是一個最長上升子序列的變形,題目給你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 ;
}