作者:disappearedgod
时间:2014-6-10
前言
本文从《算法导论》入手,然后加上一些自己的见解。
首先,先来谈一谈我们为什么需要动态规划。
其实,对于计算机能解决的问题的讨论一直没有个定理,而关于计算机解决的问题的这个话题也成为了一门学科,笼统的认识就是P类问题可解,NP问题不可解。而动态规划的解决范围又比计算机能解决的范围来的少,那么我们为什么将DP作为我们计算机领域的一个认知常识来学习呢?
我认为,DP得到了计算机视角解释解决问题的真谛。对于算法可以解决的问题来说,它节省了递归算法的重算的费力的时间实在太多,而且比贪心算法更在乎全局性最优,而不是局部。
从思考问题来说,用DP的想法来看,对于世界的理解也许能上升一个档次。
从写论文来看,DP是一切解释动态性问题的基本,是Evolution类算法的鼻祖。随着计算社会学的研究深入,DP成为不可或缺的一个算法。
目录
正文
15 动态规划
动态规划(dynamic programming)是通过组合子问题的解而解决整个问题的。动态规划只求解一次,将其结果保存在一张表中,从而避免每次到各个子问题时重新计算答案。
动态规划算法的设计可以分为下列4个步骤:
- 描述最优解的结构。
- 递归定义最优解的值。
- 按自底向上的方法计算最优解的值。
- 由计算的结果构造一个最优解。
15.1 装配线调度
算法导论上给出了一个求解工厂流水线问题的解法
步骤1:通过工厂最快路线的结构
步骤2:一个递归的解
步骤3:计算最快时间
步骤4:构造通过工厂的最快路线
15.2 矩阵链乘法
计算全部括号的重数
15.2.1 步骤一:最优加全部括号的结构
15.2.2 步骤二:一个递归解
15.2.3 步骤三:计算最优代价
15.2.4 步骤四:构造一个最优解
15.3 动态规划基础
什么时候需要动态规划?——适合采用动态规划方法的最优化问题中的两个要素:最优子结构和重叠子问题。另外,还要分析一种不同的方法:成为备忘录(memoization
),以充分利用重叠子问题性质。
最优子结构
用动态规划求解优化问题的第一步是描述最优解的结构。
在找寻最优子结构时,可以遵循一种共同的模式:
- 问题的一个解可以是一个选择。
- 假设对一个给定的问题,已知的是一个可以导致最优解的选择。
- 在已知这个选择后,要确定那些子问题会随之发生,以及如何最好的描述所得到的子问题空间。
- 利用一种cut-and-paste技术,来证明在问题的一个最优解中,使用的子问题的姐本身必须是最优的。(通过假设每一个子问题的姐都不是最优解,然后导出矛盾,即可做到这一点)
最优子结构在问题域中以两种方式变化:
- 有多少个子问题被使用在原问题的一个最优解中
- 在决定一个最优解中适用哪些子问题时有多少个选择。
非正式地,一个动态规划算法的运行时间依赖于两个因素的乘积:子问题的总个数和每个子问题中有多少种选择。
Tips:贪心算法与动态规划有着很多相似之处。特别地,贪心算法适用的问题也具有最优子结构。贪心算法与动态规划有一个显著的区别:贪心算法中,是以自顶向下的方式使用最优子结构的。
一些细微之处
这里想说的就是:要注意在不能应用最优子结构的时候,就一定不能假设它能够应用。
无权最短路径:
找出一条从u到v的包含最少边数的路径。这样的一条路径必须是简单路径,因为从路径中去掉一个回路后,会产生变数更少的路径。
无权最长简单路径:
找出一条从u到v的包含最多变数的简单路径(无环)。我们需要加入简单性的要求,否则,就可以随意地遍历一个回路任意多次来得到有任意多的边数的路径。
对于这两个问题,无权最短路径具有最优子结构(可以用剪贴法来论证);而后者没有,而它是一个NP-Complete事件。
重叠子问题
这个问题其实是DP比递归具有优势的重要原因。
重新构造一个最优解
做备忘录
15.4 最长公共子序列
15.4.1 步骤一:描述一个最长公共子序列
定理15.1 (LSC的最优子结构)
15.4.2 步骤二:一个递归解
15.4.3 步骤三:计算LCS的长度
15.4.4 步骤四:构造一个:LCS