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

题目

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

题目大意

有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 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));
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值