01 动态规划
动态规划(dynamic programming)与分治法相似, 都是通过组合子问题的解来求解原问题. 分治方法将问题划分为互不相交的子问题, 递归地求解子问题, 在将它们的解组合起来, 求出原问题的解. 而动态规划应用与子问题重叠的情况, 即不同的子问题具有公共的子问题. 对于分治法来说会重复的计算公共的子问题. 而动态规划对子问题只求解一次, 将结果保存到表格中(相当于缓存),以后用的时候直接取出即可.
动态规划通常用来求解最优化问题. 比如咱们使用地图导航寻找最短路径问题等.
动态规划算法的4个步骤:
1、找到最优解的结构特征, 这步其实最难.
2、递归地定义最优解的值.
3、计算最优解的值, 通常采用自底向上的方法.
4、利用计算出的信息构造一个最优解.
02 动态规划样例: 钢条切割
此表表示钢条的长度带来的价格, 比如长度为8的钢条带来20元的收益.
问题是这样: 给定一段长度为n英寸的钢条和一个价格表pi(如上图), 求切割钢条方案, 使销售收益rn最大. 若长度为n英寸的钢条价格pn足够大, 最优解可能就是完全不需要切割.
长度为n英寸的钢条共有2的n-1次方种不同的切割方案, 因为在距离钢条左端i英寸处, 总是可以选择切割或不切割. 我们用7 = 2 + 2 + 3 表示长度为7英寸的钢条切割为三段. 两段长为2英寸, 一段长为3英寸. 若一个最优解将钢条切割为k段, 那么最优切割方案 n = i1 + i2 + i3 + …+ ik, 得到的最大收益为rn = pi1+pi2+…+pik. 我们对应上表最优收益值及对应的最优切割方案:
上面理解起来应该不难, 更一般地, 对于rn(n>=1), 最优收益我们记为:
rn = max(pn, r1+r(n-1), r2 + r(n-2),…, r(n-1) + r1), 第一个参数pn对应不切割, 直接出售长度为n英寸的钢条的方案. 其他n-1个参数对应另外n-1种方案: 对每个i=1, 2,…,n-1, 首先将钢条切割为长度为i和n-i两段, 接着求解这两段的最优切割收益ri和r(n-i),(每种方案的最优收益为两段的最优收益之和). 由于无法知道哪种方案会获得最优收益, 我们必须考察所有可能的i, 选出收益最大的.
最优子结构: 问题的最优解由相关子问题的最优解组合而成, 而这些子问题可以独立求解.
03 自顶向下递归实现
# coding=utf-8
def CUT_ROD(p, n):
"""
自顶向下递归实现
"""
q = -65535
if n == 0:
return 0
for i in range(0, n):
q = max(q, p[i] + CUT_ROD(p, n-i-1))
return q
if __name__ == '__main__':
p = [1, 5, 8, 9, 10, 17, 17, 20, 24, 3