题目
题目粘贴格式有问题,请自行点击
题目大意
有N种长方体,每种无限个,从其中选出一些叠成一根柱子(长方体可以旋转),使得上面的长方体的长和宽严格小于下面长方体的长和宽,求柱子的最大高度。
思路
“上面的严格小于下面的”,看到这种题,瞬间想到了最长上升子序列。
只是条件从1个变为了2个,多了“长方体无限多”的条件而已。
首先解决第一个:长和宽都要严格小于前面的。这还用解决吗……if里面多加一个条件就好了。或者你装逼可以重载运算符。
第二个,仔细想想,1个长方体最多能用3次,为什么?假设这个长方体的长宽高分别为a,b,c,那么这个长方体的底面只有可能是:a*b
,b*c
,a*c
三种。假如下面一个长方体的底面为a*b
,上面的长方体最多只能选b*c
或a*c
,如果上面的长方体的底面也为a*b
,就不满足“严格小于”的条件了。如果中间又隔了几个长方体,就更不可能是a*b
了,所以一个长方体以a*b
,b*c
,a*c
各作底面一次,也就只能用3次了。
也就是说,存的时候每个长方体存3次,分别以长,宽,高为高。
DP前先按底面排个序,然后和最长上升子序列做法一模一样。
代码
#include<cstdio>
#include<algorithm>
using namespace std;
int read()
{
int x=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
return x*f;
}
#define MAXN 30
#define INF 0x7fffffff
struct Cube
{
int size[3];//存长,宽,高
}c[MAXN*3+5];//注意开3倍空间(话说我之前没开3倍也AC了,数据是有多水……)
int N;
int f[MAXN*3+5];
bool cmp(Cube x,Cube y)//按底面(先长后宽)排序
{
if(x.size[0]!=y.size[0]) return x.size[0]<y.size[0];
return x.size[1]<y.size[1];
}
int DP(int n)
{
int ans=-1;
for(int i=1;i<=n;i++)
{
f[i]=c[i].size[2];
for(int j=1;j<=i;j++)
if(c[j].size[0]<c[i].size[0]&&c[j].size[1]<c[i].size[1]&&f[i]<f[j]+c[i].size[2])//和最长上升子序列几乎相同,只是最长上升子序列每次加1,这个每次加上长方体的高
f[i]=f[j]+c[i].size[2];
ans=max(ans,f[i]);
}
return ans;
}
int main()
{
int cas=0;
while(1)
{
N=read();
if(!N) return 0;
int tN=0;
for(int i=1;i<=N;i++)
{
int x=read(),y=read(),z=read();
c[++tN].size[0]=max(x,y);c[tN].size[1]=min(x,y);c[tN].size[2]=z;
c[++tN].size[0]=max(y,z);c[tN].size[1]=min(y,z);c[tN].size[2]=x;
c[++tN].size[0]=max(x,z);c[tN].size[1]=min(x,z);c[tN].size[2]=y;//存3次,保证长>=宽
}
sort(c+1,c+tN+1,cmp);//排序
printf("Case %d: maximum height = %d\n",++cas,DP(tN));
}
}