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. 【C# .Net GC】清除非托管类型(Finalize终结器、dispose模式以及safeHandler)

    总结 1.一般要获取一个内核对象的引用,最好用SafeHandle来引用它,这个类可以帮你管理引用计数,而且用它引用内核对象,代码更健壮 2.托管中生成并引用非托管,一但非托管和托管中的引用断开(托管 ...

  2. Oracle之单行函数(字符串函数/数字函数/转换函数/日期函数/通用函数)

    虚拟表DUAL介绍: dual是一张虚拟表,只有一行一列,用来构成select的语法规则. Oracle的查询中,必须使用"select 列- from 表"的完整语法,当查询单行 ...

  3. urllib-访问网页的两种方式:GET与POST

    学习自:https://www.jianshu.com/p/4c3e228940c8 使用参数.关键字访问服务器 访问网络的两种方法: 1.GET 利用参数给服务器传递信息 参数data为dict类型 ...

  4. spring boot application.yml 常用基本配置

    1.Tomcat 配置 server: #设置请求端口 port: 8080 servlet: #指定 Tomcat的请求路径 context-path: /cl #设置 Tomcat 编码格式 en ...

  5. JZ-017-树的子结构

    树的子结构 题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) 题目链接: 树的子结构 代码 /** * 标题:树的子结构 * 题目描述 * 输入两棵 ...

  6. 【FAQ】接入HMS Core推送服务过程中一些常见问题总结

    HMS Core 推送服务(Push Kit)是华为提供的消息推送平台,建立了从云端到终端的消息推送通道.开发者通过集成推送服务,可以向客户端应用实时推送消息,构筑良好的用户关系,提升用户的感知度和活 ...

  7. 实践1使用XGB实现酒店信息消歧

    XGB算法是决策树衍生出来的一种算法 场景:酒店的业务人员希望我们能够提供一个算法服务去为酒店信息做一个自动化的匹配,以通过算法的手段,找到那些确定相同的酒店和确定不同的酒店 以下代码为部分 理解业务 ...

  8. 36 异常机制 自定义异常 实际应用中的经验总结 尽量添加finally语句块去释放占用的资源

    自定义异常 概念 使用Java内置的异常可以描述在编辑时出现的大部分异常情况.除此之外,用户还可以自定义异常.用户自定义异常类,只需继承Exception类即可. 在程序中使用自定义异常类,大体可分为 ...

  9. Kernel pwn 基础教程之 ret2usr 与 bypass_smep

    一.前言 在我们的pwn学习过程中,能够很明显的感觉到开发人员们为了阻止某些利用手段而增加的保护机制,往往这些保护机制又会引发出新的bypass技巧,像是我们非常熟悉的Shellcode与NX,NX与 ...

  10. unity 加载网络图片

    摘要:利用Http加载网络图片. 解决思路: 1.直接用unity 自带的www加载,在高版本www已经过时了. 2.本文直接使用万能的文件流加载. (1)使用System.Net.HttpWebRe ...