【动态规划】UVa 437 The Tower of Babylon

来源:互联网 发布:php开发服务器端 编辑:程序博客网 时间:2024/05/20 17:59

题目

题目粘贴格式有问题,请自行点击

题目大意

有N种长方体,每种无限个,从其中选出一些叠成一根柱子(长方体可以旋转),使得上面的长方体的长和宽严格小于下面长方体的长和宽,求柱子的最大高度。

思路

“上面的严格小于下面的”,看到这种题,瞬间想到了最长上升子序列。
只是条件从1个变为了2个,多了“长方体无限多”的条件而已。

首先解决第一个:长和宽都要严格小于前面的。这还用解决吗……if里面多加一个条件就好了。或者你装逼可以重载运算符。

第二个,仔细想想,1个长方体最多能用3次,为什么?假设这个长方体的长宽高分别为a,b,c,那么这个长方体的底面只有可能是:a*b,b*c,a*c三种。假如下面一个长方体的底面为a*b,上面的长方体最多只能选b*ca*c,如果上面的长方体的底面也为a*b,就不满足“严格小于”的条件了。如果中间又隔了几个长方体,就更不可能是a*b了,所以一个长方体以a*bb*ca*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 0x7fffffffstruct 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));    }}