UVA437 The Tower of Babylon

题解

初始时给了 \(n\) 种长方体方块,每种有无限个,对于每一个方块,我们可以选择一面作为底。然后用这些方块尽可能高地堆叠成一个塔,要求只有一个方块的底的两条边严格小于另一个方块的底的两条边,这个方块才能堆在另一个上面

问题的思考在于每种方块有无限个,如果我们直接利用该条件问题会变得比较复杂。其实仔细考虑方块堆叠的要求,会发现这是一个约束很强的条件。

注意到,方块堆叠的要求描述的对象不只是方块本身,更细地说,它应该描述的是方块摆放方式。一个长方体方块有三个面可以作为底(另三个面为对面,面与面对应相同),选择其中一个面后又需要再分两种摆放方式。所以对每种方块应该有六种摆放方式。用向量可以描述这六种摆放方式。前两个数字表示底面的长和宽,第三个数字表示高。

  1. \((x_i, y_i, z_i)\)
  2. \((y_i, x_i, z_i)\)
  3. \((y_i, z_i, x_i)\)
  4. \((z_i, y_i, x_i)\)
  5. \((x_i, z_i, y_i)\)
  6. \((z_i, x_i, y_i)\)

根据方块堆叠的要求,我们可以进一步得出,每种方块摆放方式(共 \(6n\) 种)在堆叠过程中最多出现一次。否则,存在一种摆放方式至少出现了两次,对于该种方块摆放方式,无论谁在上谁在下,都会存在一个方块的底的两条边等于另一个方块的底的两条边的情况,与严格小于相悖。所以对于每种方块摆放方式,我们可以选择“摆放”或是“不摆放”。

我们进一步思考方块堆叠的要求,它要保证底的两条边都得严格小于另一底的两条边,因此我们可以先对其中一条边做一个排序,再保证“选出的所有方块”的另一条边堆叠时依次严格小于即可。也就是说可以将二维的问题通过预处理排序将为一维的问题,而且可以进一步发现该一维问题是比较典型的动态规划问题(最长上升子序列)。

对在 \(x\) 轴上的每条边做一个排序(从大到小),然后根据 \(y\) 轴上的边的值选择“摆放”或是“不摆放”,最后要使得 \(z\) 轴上的值加和最大。使用一维 \(dp\) 数组记录状态,\(dp[i]\) 表示以第 \(i\) 个已摆放的前 \(i\) 个方块摆放方式的最大高度。

状态转移方程

\(dp[i]\) 状态表示已经“摆放”了第 \(i\) 号方块摆放方式,达到最大高度的堆叠方式可能需要垫一个方块,也可能不需要。如果垫一个方块则该方块的摆放方式只能是前面 \(i-1\) 个方块摆放方式中的一个(预处理时已将方块摆放方式排序,后面的方块一定不满足要求),由此可得状态转移方程:

\[dp[i] = \max \left( \max_{0 \leqslant j \leqslant i - 1} dp(j), 0 \right) + blocks[i].g
\]

状态搜索方向

直接将 \(dp[i]\) 从左至右依次更新即可。

程序:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std; int n, x, y, z, cnt = 0;
struct node {
int c, k, g;
node(int x, int y, int z) {
c = x; k = y; g = z;
}
};
vector<node> blocks;
int dp[305]; bool cmp(node a, node b) {
if (a.c > b.c) return true;
else if (a.c == b.c) {
if (a.g > b.g) return true;
else return false;
}
else return false;
}
int main()
{
while (cin >> n && n != 0) {
blocks.clear();
for (int i = 0; i < n; ++i) {
scanf("%d %d %d", &x, &y, &z);
// 每个方块六种摆放方式
blocks.push_back(node(x, y, z));
blocks.push_back(node(y, x, z));
blocks.push_back(node(x, z, y));
blocks.push_back(node(z, x, y));
blocks.push_back(node(z, y, x));
blocks.push_back(node(y, z, x));
}
// 排序
sort(blocks.begin(), blocks.end(), cmp);
memset(dp, -1, sizeof(dp));
int ans = -1;
for (int i = 0; i < 6 * n; ++i) {
dp[i] = blocks[i].g;
for (int j = 0; j < i; ++j) {
if (blocks[i].c < blocks[j].c && blocks[i].k < blocks[j].k)
dp[i] = max(dp[j] + blocks[i].g, dp[i]);
}
ans = max(ans, dp[i]);
}
printf("Case %d: maximum height = %d\n", ++cnt, ans);
}
return 0;
}

ACM - 动态规划 - UVA437 The Tower of Babylon的更多相关文章

  1. [动态规划]UVA437 - The Tower of Babylon

     The Tower of Babylon  Perhaps you have heard of the legend of the Tower of Babylon. Nowadays many d ...

  2. Uva437 The Tower of Babylon

    https://odzkskevi.qnssl.com/5e1fdf8cae5d11a8f572bae96d6095c0?v=1507521965 Perhaps you have heard of ...

  3. UVa437 The Tower of Babylon(巴比伦塔)

    题目 有n(n<=30)种立方体,每种有无穷多个,摞成尽量高的柱子,要求上面的立方体要严格小于下面的立方体. 原题链接 分析 顶面的大小会影响后续的决策,但不能直接用d[a][b]来表示,因为可 ...

  4. 【DP】【Uva437】UVA437 The Tower of Babylon

    传送门 Description Input Output Sample Input Sample Output Case : maximum height = Case : maximum heigh ...

  5. UVa 437 The Tower of Babylon(经典动态规划)

    传送门 Description Perhaps you have heard of the legend of the Tower of Babylon. Nowadays many details ...

  6. UVA437-The Tower of Babylon(动态规划基础)

    Problem UVA437-The Tower of Babylon Accept: 3648  Submit: 12532Time Limit: 3000 mSec Problem Descrip ...

  7. DAG 动态规划 巴比伦塔 B - The Tower of Babylon

    题目:The Tower of Babylon 这是一个DAG 模型,有两种常规解法 1.记忆化搜索, 写函数,去查找上一个符合的值,不断递归 2.递推法 方法一:记忆化搜索 #include < ...

  8. UVa 437 The Tower of Babylon

    Description   Perhaps you have heard of the legend of the Tower of Babylon. Nowadays many details of ...

  9. POJ 2241 The Tower of Babylon

    The Tower of Babylon Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on PKU. Or ...

随机推荐

  1. Ubuntu更新命令无法执行的,下一步该怎么办?

    对Linux的系统学习的更加深入,所以今天笔者正在Ubuntu20.04 LTS 上部署Sublime Text 的环境时 , 由于对操作的不熟悉,踩了一些坑.拿出来和大家分享. 正在我对照着官方文档 ...

  2. 解决gpg failed to sign the data fatal: failed to write commit object解决方案

    今天有位新同事在comit代码的时候一直报这个错误: gpg failed to sign the data fatal: failed to write commit object. 看到网上说gp ...

  3. spring 使用depends-on, lazy-init, defalut-lazy-init

    depends-on 如果一个bean是另一个bean的依赖, 可以使用ref属性或者<ref/>标签来实现依赖 那么被依赖bean一定是要比依赖bean率先实例化, 而depends-o ...

  4. centos7 部署ansible

    Ansible默认采用SSH的方式管理客户端,基于python开发,由paramiko和PyYAMl 两个关键模块构建 支持非root用户管理,支持sudo ansible作用:通过使用ansible ...

  5. JZ-027-字符串的排列

    字符串的排列 题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则按字典序打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和c ...

  6. JZ-019-顺时针打印矩阵

    顺时针打印矩阵 题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4 矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 ...

  7. 配置DHCP Relay的功能原理是什么?

    DHCP中继代理,就是在DHCP服务器和客户端之间转发DHCP数据包.当DHCP客户端与服务器不在同一个子网上,就必须有DHCP中继代理来转发DHCP请求和应答消息.DHCP中继代理的数据转发,与通常 ...

  8. 10 Java的方法 可变参数

    5.可变参数 JDK 1.5开始,Java支持传递同类型的可变参数给一个方法. 在方法声明中,在制定参数类型后加一个省略号(-). 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数.任何普通 ...

  9. Hibernate学习笔记(一)-->数据库单表操作

    Hibernate框架是一个全ORM映射框架,是一个非常流行的数据库操作框架之一,现在比较流行的还有MyBatis半ORM映射框架 在MyEclipse IDE开发工具中,可以很轻松的搭建Hibern ...

  10. 通过Geth搭建私有以太坊网络

    前言 为了进一步了解以太坊区块链网络的工作方式和运行原理,笔者通过官方软件Geth搭建了私有以太坊网络fantasynetwork,最终实现了单机和多机节点间的相互连通:首先通过VMware Work ...