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


      解释:动态规划(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

      

  • 相关阅读:
    《VC++深入详解》学习笔记 第十二章 文件和注册表操作
    《VC++深入详解》学习笔记 第九章 定制应用程序外观
    《VC++深入详解》学习笔记 第七、八章对话框
    《VC++深入详解》学习笔记 第六章 菜单
    《VC++深入详解》学习笔记 第五章 文本编程
    《VC++深入详解》学习笔记 第四章 简单绘图
    《VC++深入详解》学习笔记 第三章 MFC框架程序剖析
    Inno_Setup使用笔记(简单完成安装包制作)
    《VC++深入详解》学习笔记 第一章 Windows程序内部运行机制
    搭建eclipse的nodejs开发环境图解
  • 原文地址:https://www.cnblogs.com/SHOR/p/6368828.html
Copyright © 2020-2023  润新知