《算法图解》学习笔记—第9章 动态规划

前言

 需要在给定约束条件下优化某种指标时,动态规划很有用。
 问题可分解为离散子问题时,可使用动态规划来解决。
 每种动态规划解决方案都涉及网格。
 单元格中的值通常就是你要优化的值。
 每个单元格都是一个子问题,因此你需要考虑如何将问题分解为子问题。


背包问题

小偷背着一个可装4磅东西的背包,可盗窃的商品有如下3件。为了让盗窃的商品价值最高,该选择哪些商品?
在这里插入图片描述
近似解方法找到的可能不是最优解。那么如何找到最优解呢?

每个动态规划算法都从一个网格开始,背包问题的网格如下。

在这里插入图片描述
第一行是吉他行,意味着你将尝试将吉他装入背包。在每个单元格,都需要做一个简单的决定:偷不偷吉他?目标是找出一个价值最高的商品集合。
在这里插入图片描述
填充下一行——音响行。可偷的商品有吉他和音响。在每一行,可偷的商品都为当前行的商品以及之前各行的商品。
在这里插入图片描述
逐步更新最大价值
在这里插入图片描述
以同样的方式处理笔记本电脑
在这里插入图片描述
对于容量为4磅的背包,情况很有趣。这是非常重要的部分。当前的最大价值为3000美元,你可不偷音响,而偷笔记本电脑,但它只值2000美元。
在这里插入图片描述
价值没有原来高。但等一等,笔记本电脑的重量只有3磅,背包还有1磅的容量没用!

在这里插入图片描述
在1磅的容量中,可装入的商品的最大价值是多少呢?你之前计算过。
在这里插入图片描述
根据之前计算的最大价值可知,在1磅的容量中可装入吉他,价值1500美元。因此,你需要做如下比较。
在这里插入图片描述
笔记本电脑和吉他的总价值为3500美元,因此偷它们是更好的选择。最终的网格类似于下面这样。
在这里插入图片描述

计算每个单元格的价值时,使用的公式都相同。这个公式如下:
在这里插入图片描述

各行的排列顺序无关紧要。

增加一件更小的商品时,需要考虑的粒度更细,因此必须调整网格。
在这里插入图片描述
不考虑偷商品的一部分
使用动态规划时,要么考虑拿走整件商品,要么考虑不拿,而没法判断该不该拿走商品的一部分。
但使用贪婪算法可轻松地处理这种情况!首先,尽可能多地拿价值最高的商品;如果拿光了,再尽可能多地拿价值次高的商品,以此类推。

旅游行程最优化

对于想去游览的每个名胜,都列出所需的时间以及你有多想去看看。根据这个清单,确定两天时间该去游览哪些名胜。
在这里插入图片描述
网格类似于下面这样。
在这里插入图片描述
假设你还想去巴黎,因此在前述清单中又添加了几项。
在这里插入图片描述

从伦敦前往巴黎,这需要半天时间。不是去每个地方都得先从伦敦到巴黎。将埃菲尔铁塔加入“背包”后,卢浮宫将更“便宜”:只要1天时间,而不是1.5天。

动态规划能够解决子问题并使用这些答案来解决大问题。但仅当每个子问题都是离散的,即不依赖于其他子问题时,动态规划才管用。这意味着使用动态规划算法解决不了去巴黎玩的问题。

最长公共子串

用户在网站输入单词时,需要给出其定义。但如果用户拼错了,必须猜测他原本要输入的是什么单词。例如,Alex想查单词fish,但不小心输入了hish。但网站的字典中,根本就没有这样的单词,但有几个类似的单词。你需要判断是哪个。在这里插入图片描述

在这个例子中,你要找出两个单词的最长公共子串。

用于解决这个问题的网格是什么样的呢?要确定这一点,你得回答如下问题。
 单元格中的值是什么?
 如何将这个问题划分为子问题?
 网格的坐标轴是什么?

单元格中的值通常就是你要优化的值。在这个例子中,这很可能是一个数字:两个字符串都包含的最长子串的长度。

如何将这个问题划分为子问题呢?你可能需要比较子串:不是比较hish和fish,而是先比较his和fis。每个单元格都将包含这两个子串的最长公共子串的长度。这也给你提供了线索,让你觉得坐标轴很可能是这两个单词。因此,网格可能类似于下面这样。在这里插入图片描述

最终的网格如下:
在这里插入图片描述
伪代码如下:

if word_a[i] == word_b[j]:
    cell[i][j] = cell[i-1][j-1] + 1
else:
    cell[i][j] = 0

查找单词hish和vista的最长公共子串时,网格如下。
在这里插入图片描述

但对于最长公共子串问题,答案为网格中最大的数字——它可能并不位于最后的单元格中。

最长公共子序列

假设Alex不小心输入了fosh,他原本想输入的是fish还是fort呢?

我们使用最长公共子串公式来比较它们。
在这里插入图片描述
最长公共子串的长度相同,都包含两个字母!但fosh与fish更像。

这里比较的是最长公共子串,但其实应比较最长公共子序列:两个单词中都有的序列包含的字母数。
在这里插入图片描述

下面是填写各个单元格时使用的公式。
在这里插入图片描述
伪代码如下:

if word_a[i] == word_b[j]:
    cell[i][j] = cell[i-1][j-1] + 1
else:
    cell[i][j] = max(cell[i-1][j], cell[i][j-1])

动态规划都有哪些实际应用呢?
 生物学家根据最长公共序列来确定DNA链的相似性,进而判断度两种动物或疾病有多相似。最长公共序列还被用来寻找多发性硬化症治疗方案。
 你使用过诸如git diff等命令吗?它们指出两个文件的差异,也是使用动态规划实现的。
 前面讨论了字符串的相似程度。编辑距离(levenshtein distance)指出了两个字符串的相似程度,也是使用动态规划计算得到的。编辑距离算法的用途很多,从拼写检查到判断用户上传的资料是否是盗版,都在其中。
 你使用过诸如Microsoft Word等具有断字功能的应用程序吗?它们如何确定在什么地方断字以确保行长一致呢?使用动态规划!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值