UVA437 The Tower of Babylon(DAG上的动态规划)

题目大意

有n(n<=30)种长方体,每种都有无穷多个。要求选一些长方体摞成一根尽量高的柱子(可以自行选择一条边作为高),使得每个长方体的底面长宽分别严格小于它下方立方体的地面长宽。

解题思路

这是一个DAG(有向无环图)模型。每种长方体将长宽高全排列变成6个长方体,这就够了,因为题目的限制,这六个长方体最多被使用一次。定义dp[i]表示以第i个长方体为顶时柱子的最大高度。对于每个长方体Ai,遍历其他长方体Bj,如过Bj能成为Ai的顶,并且当Bj放在Ai上时dp[j]变大,那么更新dp[j]。
注意:我们需要事先对所有长方体进行排序,这样才能保证当i更新完j之后,dp[j]的值是j以0~i这些长方体为底时的最优解,这样才能保证j去更新其他长方体时也能使其他长方体得到最优解。

参考代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
struct Block{
    int x,y,z;
};
vector<Block> vec;
int dp[1005]; //表示以第i块砖为顶的柱子最大高度 
bool isOk(Block a,Block b){     //判断b是否能放在a上面 
    return  (a.x>b.x&&a.y>b.y); 
}   
bool cmp(Block a,Block b){
    if(a.x==b.x)            
        return a.y>b.y;
    else return a.x>b.x;    //以x为主降序排列 
}
int main(){
    int n,x,y,z,t=0;
    while (cin >> n,n){
        vec.clear();
        memset(dp,0,sizeof(dp));
        for(int i=0; i<n; i++){
            cin >> x >> y >> z;
            vec.push_back(Block{x,y,z});
            vec.push_back(Block{x,z,y});
            vec.push_back(Block{y,x,z});
            vec.push_back(Block{y,z,x});
            vec.push_back(Block{z,x,y});
            vec.push_back(Block{z,y,x}); 
        }
        int Max=0;
        sort(vec.begin(),vec.end(),cmp); 
        for(int i=0; i<vec.size(); i++){
            dp[i]=vec[i].z;
            Max=max(Max,dp[i]);
        }
        for(int i=0; i<vec.size(); i++){
            for(int j=i+1; j<vec.size(); j++){
                Block a=vec[i],b=vec[j];
                if(isOk(a,b)&&dp[j]<dp[i]+b.z){     //当b能放在a上面且这样以b为顶的柱子更高 
                    dp[j]=dp[i]+b.z;
                    Max=max(Max,dp[j]);
                }
            }
        }
        printf("Case %d: maximum height = %d\n",++t,Max);
    }
    return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值