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. weblogic补丁安装失败

    转至:https://www.cnblogs.com/lsdb/p/7234989.html weblogic补丁安装失败(Patch B25A is mutually exclusive and c ...

  2. Redis-基本概念、java操作redis、springboot整合redis,分布式缓存,分布式session管理等

    NoSQL的引言 Redis数据库相关指令 Redis持久化相关机制 SpringBoot操作Redis Redis分布式缓存实现 Resis中主从复制架构和哨兵机制 Redis集群搭建 Redis实 ...

  3. HTML的怎么使用,开发工具以及常用标签。

    前端学习:学习地址:黑马程序员pink老师前端入门教程,零基础必看的h5(html5)+css3+移动,下面这些都是一些学习笔记.临渊羡鱼,不如退而结网!!愿我自己学有所成,也愿每个前端爱好者学有所成 ...

  4. SpringBoot 搭建基于 MinIO 的高性能存储服务

    1.什么是MinIO MinIO是根据GNU Affero通用公共许可证v3.0发布的高性能对象存储.它与Amazon S3云存储服务兼容.使用MinIO构建用于机器学习,分析和应用程序数据工作负载的 ...

  5. c++11 实现枚举值到枚举名的转换

    效果 ``` ENUM_DEFINE ( Color, Red, Blue, ) EnumHelper(Color::Red) -> "Red" EnumHelper(Col ...

  6. php在windows上安装kafka扩展

    一.下载kafka扩展包 链接:https://pecl.php.net/package/rdkafka 二.解压安装包 三.修改php.ini 复制librdkafka.dll 到php\php7. ...

  7. 理解并手写 apply() 函数

    apply()函数,在功能上类似于call(),只是传递参数的格式有所不同. dog.eat.call(cat, '鱼', '肉'); dog.eat.apply(cat, ['鱼', '肉']); ...

  8. 如何实现ARC中weak功能?

    原文链接 我们都知道ARC中weak与assign或者说unsafe_unretained最大的不同就是设置weak属性后,系统会在对象被释放后自动将指向对象的指针置为nil,而assign则会产生一 ...

  9. 25 面向对象编程 继承概念 代码 快捷键 super注意点

    继承概念 继承的本质是对某一批的抽象,从而实现对现实世界更美好的建模. extends的意思的"扩展".子类是父类的扩展. JAVA中类只有单继承,没有多继承!理解:一个儿子只能有 ...

  10. 04 变量 变量作用域 常量final 变量的命名规范

    变量 变量是什么:就是可以变化的量! Java是一种强类型语言,每个变量都必须声明其类型. Java变量是程序中最基本的存储单元,其要素包括变量名,变量类型和作用域. 注意事项: 每个变量都有类型,类 ...