目录
概念
programming:表格法
同分治算法一样,是通过组合子问题的解来解决原问题。
动态规划算法通常用于求解最优化问题。
应用于子问题重叠的情况
步骤
- 
- 分析最优解的性质,并刻画其结构特征
 
 - 
- 递归地定义最优解的值
 
 - 
- 计算最优解的值,通常采用自底向上的方法
 
 - 
- 利用计算出的信息构造一个最优解
 
 
最优解的结构特征
当完成首次切割后,我们将两段钢条看作两个独立的切割问题实。通过组合两个相关子问题的最优解,并在所有可能的两段切割中选取组合收益最大的,构成原问题的最优解。
例子
1.钢条切割
问题描述: 给定1个长度为n的钢条和钢条切割价格条目,求将钢条切割为若干 小段后,得到的最大收益。
| 长度i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 
|---|---|---|---|---|---|---|---|---|---|---|
| 价格 | 1 | 5 | 8 | 9 | 10 | 17 | 17 | 20 | 24 | 30 | 
- 
长度为n英寸
 - 
销售收益
 - 
假设最优解切割为k段,最优切割方案为
 
- 将钢条切割为k段,最大收益为
 
- 最优收益对应的最优切割方案
 
更一般的,对于,我们可以用更短的钢条最优收益来描述
指不分割的方案 钢条切割问题满足最优子结构
另一种相似但是更为简单的方案:i部分不分割,剩下的n-i部分进行分割,即问题分解的方式为:将长度为n的钢条分解为左边开始一段不分割以及剩余部分继续分解的结果,公式描述为:
CUT-ROD(p,n)
if n=0
    return 0
else
    q = -∞
    for j=1 to n
        q = max{q, p[j]+CUT-ROD(p,n-j)}
    return q
下面展示如何用动态规划解决此问题
- 1.带备忘的自顶向下法
 
仍然按照自然的递归形式编写过程,使用散列表会这数组保存已求解的子问题
MEMOIZED-CUT-ROD(p,n)
    let r[0..n] be a new Array;
    for i=0 to n
        r[i]=-∞;
    //将辅助函数r[n]的值初始化为-∞
    return MEMOIZED-CUT-ROD-AUX(p,n,r)
//上述CUT-ROD的变体,提供备忘机制
MEMOIZED-CUT-ROD-AUX(p,n,r)
    //已知直接返回
    if(r[n]>=0)
        return r[n]
    if(n==0)
        q = 0
    else
        q = -∞
        for j=1 to n
            q = max{q, p[j]+MEMOIZED-CUT-ROD-AUX(p,n-j,r)}
    //将q存入
    r[n] = q
    return q
- 2.自底向上法
 
按照问题的递归结构,自底向上求解,将子问题按照规模排序,再由小到大解决
BOTTOM-UP-CUT-ROD(p,n)
    let r[0..n] be a new Array;
    r[0] = 0
    for j=1 to n
        q = -∞
        for i=1 to j
            q = max{q, p[i]+r[j-i]}
        r[j] = q
    return r[n]
- 分析自顶向上
 
第一行创建一个新数组保存子问题的解,第二行将数组第一个值初始化为0
let r[0..n] be a new Array;
r[0] = 0
3-6行升序求解从1到n的规模为j的子问题
for j=1 to n
        q = -∞
        for i=1 to j
7行解决子问题,不必调用递归,直接访问r[j-i],即以保存的子问题的解
q = max{q, p[i]+r[j-i]}
8行将子问题的解存入数组,9行返回最优解
两种方法具有相同的渐进运行时间,
自底向上 嵌套的两层for循环
自顶向下 递归调用, 使用聚合分析,其中
 for j=1 to n
            q = max{q, p[j]+MEMOIZED-CUT-ROD-AUX(p,n-j,r)}
对每个子问题只求解一次,求解规模为 = O()
自顶向下递归树的简化版/自顶向下的子问题图
n=4 这是一个有向图,每个顶点唯一地对应一个子问题,标号代表子问题的规模
重构解
上述算法能返回最终的最优收益值,但并没有返回解本身。下面我们拓展动态规划算法,使其返回最优收益值的同时,返回一个最优解。
EXTENDED-BOTTOM-UP-CUT-ROD(p,n)
    let r[0..n] and s[0..n] be a new Array;
    r[0]=0
    for j=1 to n
        q = -∞
        for i=1 to j
            if q < p[i]+r[j-i]
                q = p[i]+r[j-i]
                s[j] = i
        r[j] = q
    return r and s
2.矩阵链乘法
矩阵乘法满足结合律,但乘法顺序不固定,所以需要求解最优乘法顺序,使得乘法次数最少