算法导论精华总结 ~ 动态规划

Posted Sooda

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法导论精华总结 ~ 动态规划相关的知识,希望对你有一定的参考价值。

  解释:动态规划(dynamic programming)与分治方法相似,都是通过组合子问题的解来求解原问题。

  优点:动态规划比分治方法高明之处在于对每个子子问题只求解一次,将其保存,无需重新计算。

  动态规划设计步骤:

    1. 刻画一个最优解的结构特征。
    2. 递归地定义最优解的值。
    3. 计算最优解的值,通常再用自底向上的方法。(维护一些额外信息,以便构造步骤4)
    4. 利用计算出的信息构造一个最优解。

钢条切割问题

  描述:给定一段长度为n英寸的钢条和一个价格表Pi(i = 1,2,...,n),求切割钢条的方案,使得销售收益Rn最大。

  价格表:

    长度i    1    2    3    4    5    6    7    8    9    10

    价格Pi    1    5    8    9    10  17  17   20  24  30

  

  我们可以明显看出来

    R1 = 1,切割方案1 = 1(无切割)

    R1 = 5,切割方案2 = 2(无切割)

    R1 = 8,切割方案3 = 3(无切割)

    R1 = 10,切割方案4 = 2 + 2

  由此可以总结出来一个公式Rn = max(Pn, R1 + Rn-1, R2 + Rn-2,..., Rn-1 + R1)

  由此可以写出自顶向下的递归实现伪代码

CUT-ROD(P,n)       //P为价格数组[1..n],n为长度为n的最大收益
    if n == 0          //如果n = 0 不会有收益,则返回0
        return 0

    q = -无穷          //把最大收益初始化为负无穷

    for i = 1 to n    //循环1到n的切割方式
        q = max(q,P[i] + CUT-ROD(P,n-i))  //最大收益等于当前收益或切割成n段的收益中的最大值
    
    return q           //返回最大收益

  递归的弊病:你会发现一个问题,这个计算非常的慢,在n=40的情况下,就基本得算好几分钟。之所以效率这么差的原因在于,这个函数反复计算相同的参数的递归调用。即反复求解相同的子问题。

  动态规划的实质:这时候就需要动态规划的出现了,动态规划会仔细安排求解顺序,对每个子问题只求解一次,并将结果保存下来。随后再次需要此子问题的解,只需要找保存的结果,而不必重新计算。因此归根结底,动态规划是付出额外的内存空间来节省计算时间,是典型的时空权衡。

动态规划的两种实现方法

  第一种  带备忘的自顶向下法

  第二种  自底向上法

  第一种仍然是递归,只不过加了一个数组来存储每个子问题的解。

  第二种就是从小问题解决,在逐渐推出大问题,类似于一道题的自然衍生过程。

  

  对于钢条切割的第一种方法伪代码

MEMOIZED-CUT-ROD(P,n)
    let r[0..n] be a new array //新建新的数组r
    for i = 0 to n //初始化r
        r[i] = -无穷
    return MEMOIZED-CUT-ROD-AUX(P,n,r) 


MEMOIZED-CUT-ROD-AUX(P,n,r)
    if r[n] >= 0 //如果r[n] >= 0说明这个切割算过一次,直接返回结果
        return r[n]
    if n == 0 //如果切割条数为0,则返回0
        q = 0
    else 
        q = -无穷 //初始化
        for i = 1 to n
            q = max(q, P[i] + MEMOIZED-CUT-ROD-AUX(P, n-i, r)) //最优切割价格为当前价格或切割数为n-i的价格最大值
    r[n] = q //将最优切割值记录
    return q

  第二种方法的伪代码

BOTTOM-UP-CUT-ROD(P,n)
    let r[0..n] be a new array //新建r数组
    r[0] = 0     //初始化 0切割返回0
    for j = 1 to n  //循环从1条到n条长的最优解
        q = -无穷
        for i = 1 to j //循环从1切割到j切割的最优解
            q = max(q, P[i] + r[j-i]) //最优解q = 当前值或长度为i的价格和长度为j-i的最优解的和的最优值
        r[j] = q //记录最优解
    return q

 

 

  

以上是关于算法导论精华总结 ~ 动态规划的主要内容,如果未能解决你的问题,请参考以下文章

算法导论—矩阵链乘法(动态规划)

算法导论-动态规划原理

算法导论_第十六章_动态规划_creatshare分享会

算法导论之动态规划 字符串拆分问题

《算法导论》中动态规划求解钢条切割问题

算法导论动态规划 15.1-3 钢条切割问题