算法图解part9:动态规划

算法图解part9:动态规划

  • 1.动态规划(dynamic programming)
  • 2.背包问题
    • 2.1 简单算法
    • 2.2 动态规划
  • 3.背包问题FAQ
  • 4.旅行行程最大化
  • 5 最长公共子串
    • 5.1 绘制网格
    • 5.2 填充网格
    • 5.3 揭晓答案
    • 5.4 最长公共子序列
      • 5.4.1 最长公共子序列问题
      • 5.4.2 最长公共子序列解决方案:
  • 6 实际应用&练习
  • 7.总结
  • 8.参考资料

1.动态规划(dynamic programming)

百度百科
动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。1957年出版了他的名著《Dynamic Programming》,这是该领域的第一本著作。

简单直接的描述,就是指动态规划先解决子问题,再逐步解决大问题。

公式: 算法图解part9:动态规划_第1张图片

与分而治之(part4)、贪婪算法类似,动态规划算法是一种解决问题的方案。

2.背包问题

假设你是一名小偷,背着一个可装4磅的背包。
你可以盗窃的东西如下三件,为了让偷到的东西价值最高,你该选择那些商品?
算法图解part9:动态规划_第2张图片

2.1 简单算法

尝试各种可能的商品组合,并找出价值最高的组合:
算法图解part9:动态规划_第3张图片

  • 这种算法的运行时间 O ( 2 n ) O(2^n) O(2n),n为商品的数量

只要商品数量够多,这种算法就行不通。如果用贪心算法,可以找到近似解,但可能并不是最优解。
有木有其它方法找最优解呢?

2.2 动态规划

动态规划先解决子问题,再逐步解决大问题。
每个动态规划都从一个网格开始,背包问题的网格如下:

算法图解part9:动态规划_第4张图片
网格最初是空的,动态规划就是逐步将网格填满。

吉他行

第一个单元格表示背包的容量为1磅。 吉他的重量也是1磅, 这意味着它能装入背包! 因此这个单元格包含吉他, 价值为1500美元。 来看下一个单元格,这个单元格表示背包的容量为2磅, 完全能够装下吉他!这行的其他的单元格也是如此,因为你目前只能把吉他装入背包,其他两种商品还未出现,所以第一行变成下图:
算法图解part9:动态规划_第5张图片
注意:这行表示的是当前的最大价值。

音响行

现在来到第二行,在每一行,可偷的商品都是当前行的商品和之前各行的商品。因此,当前你已经解锁了音响和吉他,但是笔记本电脑还未解锁。现在来看第一个单元格,它表示容量为1磅的背包。 在此之前, 可装入1磅背包的商品的最大价值为1500美元。 背包的容量为1磅, 能装下音响吗? 音响太重了, 装不下! 由于容量1磅的背包装不下音响, 因此最大价值依然是1500美元。 接下来的两个单元格的情况与此相同。
算法图解part9:动态规划_第6张图片
现在来到了第四个单元格,也就是说背包容量为4磅,终于能装下音响,由于音响的价值为3000美元,比1500美元的吉他值钱多了,所以还是偷音响吧。
算法图解part9:动态规划_第7张图片
笔记本电脑行

下面以同样的方式处理笔记本电脑。 笔记本电脑重3磅, 没法将其装入容量为1磅或2磅的背包, 因此前两个单元格的最大价值还是1500美元。
算法图解part9:动态规划_第8张图片

对于容量为3磅的背包, 原来的最大价值为1500美元, 但现在你可选择盗窃价值2000美元的笔记本电脑而不是吉他, 这样新的最大价值将为2000美元!
算法图解part9:动态规划_第9张图片
现在来到这个问题最关键的单元格,对于容量为4磅的背包,当前的最大价值为3000美元, 你可不偷音响, 而偷笔记本电脑, 但它只值2000美元。但是笔记本电脑的重量只有3磅, 背包还有1磅的容量没用! 在1磅的容量中, 可装入的商品的最大价值之前计算过。根据之前计算的最大价值可知, 在1磅的容量中可装入吉他, 价值1500美元。于是有了下面的比较:
算法图解part9:动态规划_第10张图片
于是我们得到了最终的结果:
算法图解part9:动态规划_第11张图片
在这个过程中,我们填入单元格时用到了下面的公式:
算法图解part9:动态规划_第12张图片

3.背包问题FAQ

①沿着一列往下走时, 最大价值有可能降低吗?
答案: 不可能。 每次迭代时, 你都存储当前的最大价值。 最大价值不可能比以前低!

②行的排列顺序发生变化时结果将如何变化?
答案:没有变化。 也就是说, 各行的排列顺序无关紧要。

③可以逐列而不是逐行填充网格吗?
答案:就这个问题而言, 这没有任何影响, 但对于其他问题, 可能有影响。

④增加一件更小的商品将如何呢?
答案:单元格的按最小商品的重量划分。

⑤可以偷商品的一部分吗?
答案:没法处理。 使用动态规划时, 要么考虑拿走整件商品, 要么考虑不拿, 而没法判断该不该拿走商品的一部分。

但使用贪婪算法可轻松地处理这种情况! 首先, 尽可能多地拿价值最高的商品; 如果拿光了, 再尽可能多地拿价值次高的商品, 以此类推。 例如有以下商品可选:

算法图解part9:动态规划_第13张图片
第一个藜麦最贵,因此要尽量往背包中装藜麦!如果装满,结果就是最佳的;如果藜麦没装满,就接着装入下一个价格最高的商品,以此类推。

⑥动态规划可以处理相互依赖的情况吗?(请参考 4.旅行行程最大化的例子)
答案:没办法建模。 动态规划功能强大, 它能够解决子问题并使用这些答案来解决大问题。 但仅当每个子问题都是离散的, 即不依赖于其他子问题时, 动态规划才管用 。

⑦计算最终的解时会涉及两个以上的子背包吗?
答案:根据动态规划算法的设计, 最多只需合并两个子背包, 即根本不会涉及两个以上的子背包。 不过这些子背包可能又包含子背包。
算法图解part9:动态规划_第14张图片

4.旅行行程最大化

去伦敦度假,假期两天,但是想要游玩的地方很多,因此列个单子:
算法图解part9:动态规划_第15张图片
对于想去浏览的每个名胜,都列出所需的时间以及你有多想去看看。这里背包问题的约束条件是有限的时间。据此绘制动态规划网格。
算法图解part9:动态规划_第16张图片
答案如下:
算法图解part9:动态规划_第17张图片

  • 处理相互依赖的情况:

假如你还想去巴黎,巴黎景点如下:
算法图解part9:动态规划_第18张图片
从伦敦到巴黎,需要半天0.5天,如果三个地方都去玩,是不是总计4.5天呢?
不是的,因为,去每个地方都得先去巴黎。到达巴黎后,每个地方都只需要1天,总计3.5天即可玩完。
将埃菲尔铁塔 放入背包后,卢浮宫等 将更便宜。此时子问题是相互依赖的。

动态规划功能强大, 它能够解决子问题并使用这些答案来解决大问题。 但仅当每个子问题都是离散的, 即不依赖于其他子问题时, 动态规划才管用

5 最长公共子串

举个栗子:
Alex输入了hish,那他原本要输入的是fish还是vista呢?

5.1 绘制网格

解决上面问题的网格应该怎么构建,要考虑下面几点:

  • ①单元格中的值是什么?在这个例子中,你要找出两个单词的最长公共子串,这就是你要计算的值。
  • ②如何将这个问题划分为子问题?你可能需要比较子串:不是比较hish和fish,而是先比较his和fis。
  • ③网格的坐标轴是什么?每个单元格都将包含这两个子串的最长公共子串的长度。这也给你提供了线索,让你觉坐标轴很可能是这两个单词。

因此,网格可能类似于下面这样:
算法图解part9:动态规划_第19张图片

5.2 填充网格

填充时用什么公式呢?费曼算法(Feynman algorithm)步骤如下:(这怕不是再说废话= =!废慢算法?)

  • ①将问题写下来
  • ②好好思考
  • ③将答案写下来

5.3 揭晓答案

算法图解part9:动态规划_第20张图片
查找单词hish和vista的最长公共子串时,网格如下:
算法图解part9:动态规划_第21张图片

对于背包问题,最终答案总在最后的单元格中;但对于最长公共子串而言,答案是网格中最大的数字——不一定在最后的单元格中。

那么问题的答案出来了,hish和fish的最长公共子串包含三个字母,而hish和vista的最长公共子串包含两个字母。因此Alex很可能原本要输入的是fish。

5.4 最长公共子序列

5.4.1 最长公共子序列问题

假设Alex不小心输入了fosh,他原本想输入的是fish还是fort呢?我们使用最长公共子串公式来比较它们:
算法图解part9:动态规划_第22张图片
所以都为2,长度相同,但是fosh和fish更像。那应该找出更合适的区分公式:
比较最长公共子序列:两个单词中都有的序列包含的字母数。

5.4.2 最长公共子序列解决方案:

算法图解part9:动态规划_第23张图片
上图的公式:
算法图解part9:动态规划_第24张图片

6 实际应用&练习

动态规划的实际应用:

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

Q:请绘制并填充用来计算blue和clues最长公共子串的网格。
A:
算法图解part9:动态规划_第25张图片

7.总结

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

8.参考资料

《算法图解》第九章:详细的程序思路介绍

此部分学习算法也可参考:https://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653190796&idx=1&sn=2bf42e5783f3efd03bfb0ecd3cbbc380&chksm=8c990856bbee8140055c3429f59c8f46dc05be20b859f00fe8168efe1e6a954fdc5cfc7246b0&scene=21#wechat_redirect

你可能感兴趣的:(算法图解)