【动态规划】The Tower of Babylon 巴比伦塔

Description

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

Inout sample

1
10 20 30
2
6 8 10
5 5 5
7
1 1 1
2 2 2
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
5
31 41 59
26 53 58
97 93 23
84 62 64
33 83 27
0

Output sample

Case 1: maximum height = 40
Case 2: maximum height = 21
Case 3: maximum height = 28
Case 4: maximum height = 342

————————————————分割の线————————————————

分析

根据题意,上方立方体的底面积应当小于下方立方体的底面积,又因为每个立方体有无数个,所以可以得到一条结论

一个立方体下方的摆放不影响其上方的立方体摆放。

由此可以设f[i][j]表示到立方体i时以第j条边作为高所能达到的最高值。(a[i][j]表示第i个立方第j条边的高度)

于是就开始了对于状态转移方程的苦思冥想,
……
……
果然还是用记忆化搜索更简单

代码如下
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int f[2000][3],n;//f[i][j]表示以第i个立方体为底以第j条边为高的最大高度
int a[2000][3],cnt=0;
int dp(int u,int hight)
{
    if(f[u][hight]>=0) return f[u][hight];
    f[u][hight]=a[u][hight];//高至少为自己
    int x,y,ux,uy;//x,y为第u个立方体的长和宽
    if(hight==0)
        x=a[u][1],y=a[u][2];
    if(hight==1)
        x=a[u][0],y=a[u][2];
    if(hight==2)
        x=a[u][0],y=a[u][1];
    for(int i=1;i<=n;i++)
        for(int k=0;k<3;k++)
        {//ux,uy为第i个立方体的长和宽
            if(k==0)
                ux=a[i][1],uy=a[i][2];
            if(k==1)
                ux=a[i][0],uy=a[i][2];
            if(k==2)
                ux=a[i][0],uy=a[i][1];
            if(x>ux&&y>uy||y>ux&&x>uy)//如果满足长和宽严格小于的这个基本事实,则向下进行搜索
                if(f[u][hight]<dp(i,k)+a[u][hight])
                    f[u][hight]=a[u][hight]+dp(i,k);//保留最佳答案
    }
    return f[u][hight];
}
int main()
{
    scanf("%d",&n);
    while(n>0)//如果n不为0,则再次循环
    {
        cnt++;//记录循环次数
        for(int i=1;i<=n;i++)
            scanf("%d%d%d",&a[i][0],&a[i][1],&a[i][2]);//读入三条边
        memset(f,-1,sizeof(f));//初始化f,默认f未做过
        for(int i=1;i<=n;i++)
            for(int k=0;k<3;k++)
            {
                f[i][k]=dp(i,k);//请完成第一步,剩下的都交给记忆化搜索吧
            }
        int ans=0;
        for(int i=1;i<=n;i++)
            for(int k=0;k<3;k++)
                if(f[i][k]>ans) ans=f[i][k];//无脑枚举,求最大值
        printf("Case %d: maximum height = %d\n",cnt,ans);//按规则输出答案
        scanf("%d",&n);//再次读入n
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值