动态规划

1、前言

动态规划和分治算法非常类似,都是通过组合子问题的解来求解原问题。分治算法将问题划分为互不相交的子问题,而动态适应于子问题重叠的情况

动态规划常用于求解“最优化问题”,这类问题有很多个解,我们希望寻找最优解(最大值或最小值)

通常按如下四个步骤来设计一个动态规划算法:

  • 刻画一个最优解的结构特征
  • 递归地定义最优解的值
  • 计算最优解的值,通常采用自底向上方法
  • 利用计算出的信息构造一个最优解

或者说,动态规划有3个关键要素。

  • 1、最佳子问题(将复杂问题转化成简单问题)
  • 2、边界条件(一般是当数据量极少情况下的结果,比如n==0或n==1时的情况)
  • 3、状态转移方程(考虑 n-1 和 n这两种规模时,结果之间的推导)

2、钢条切割问题

给定一段长为n的钢条和一个价格表,求解收益最大的钢条切割方案

钢条价格

钢条价格如上,怎么切割才能有最大收益呢?通过钢条价格,我们能手动计算出钢条最佳切割方案。

最优切割方案

定义长为n的钢条切割最大收益为Rn,假设在k位置将钢条切成两段能获得最大收益,那么这两段k和n-k肯定也是最大收益,如果我们遍历循环,可得到如下公式:

最大收益

最大收益为,不切割以及从1到n-1位置切割的收益最大值。

换一个角度重新考虑,如果从1到n-1位置切割,但左边的钢条不再切割,右边的钢条使用最佳方案切割。这样得到的会不是也是最佳切割方案呢?

很明显,这种做法也是正常的,想象最终切割结果,肯定也是符合这种模式的。这样简单的递归更利于编码。

新公式

动态规划的精髓在于保存子问题的解,以提高效率。在编码中我们新定义Rn,保存n长度的最大收益,并采用自底向上方法,即先求R0,R1,再求其它,如果单纯使用暴力递归的话,效率非常低。

  public static int[] steel(int[] p){
    int[] s = new int[p.length];
    s[0] = 0;
    int max = 0;
    //因为长度为0的钢条,切割最大收益为0,S[0]已知,所以i从1开始
    for (int i = 1; i < p.length; i++) {
        max = 0;
        for (int j = 1; j <= i; j++) {
            //j也必须从1开始,如果从0开始,i等于1时,s[i-j]就等于s[1]了,而s[1]还是未知值
            if (max < (p[j] + s[i-j])) {
                max = p[j] + s[i-j];
            }
        }
        s[i] = max;
    }
    return s;
}

2、最大子数组和

给出一个数组,求最大子数组和。例如给出如下数组,最大子数组和为20

                  -2, 11, -4, 13, -5, -2

此问题解题思路和1不一样。

仔细考虑,如果设长度为n的最大子数组和为Sn,那么Sn和Sn-1有什么关系呢?动态规划最重要的思想就是将大问题分解为子问题,并由子问题求解。

直接考虑Sn和Sn-1,好像二者没有任何关系,如果我们换个角度考虑,长度为n的数组,且以n结尾的最大子数组和为Sn,这么定义的话,那么根据Sn的值,如果Sn大于0,那么Sn+1等于Sn加上a[n],如果小于0,那么Sn+1等于a[n]。

公式为:

dp[i+1] = max(dp[i]+a[i+1] , a[i+1])

  public static int getMaxSubArray(int[] array){
    int[] b = new int[array.length];
    int max = 0;
    b[0] = array[0];
    max = b[0];
    for (int i = 1; i < array.length; i++) {
        if (b[i-1] > 0) {
            b[i] = b[i-1] + array[i];
        }else {
            b[i] = array[i];
        }
        if (max < b[i]) {
            max = b[i];
        }
    }
    return max;
}

3、结语

动态规划还有其它经典问题,比如矩阵最少相乘次数,最长公共子序列,最优二叉搜索树等等。本文只讲了两个简单例子,简述动态规划的原理,可以更深入思考,二维的动态规划问题解决,以加深理解。

以上代码均已上传至本人的github,欢迎访问

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 动态规划应用于子问题重叠的情况。对于公共子问题,分治算法会做很多不必要的工作,它会反复求解公共子问题。而动态规划算...
    LRC_cheng阅读 443评论 0 1
  • 《算法导论》这门课的老师是黄刘生和张曙,两位都是老人家了,代课很慢很没有激情,不过这一章非常有意思。更多见:iii...
    mmmwhy阅读 5,334评论 5 31
  • 状态转移方程 从之前某个阶段的某个或某些状态状态到下一个状态之间的关系式,就叫做状态转移方程。 最优子结构 每个阶...
    Myth52125阅读 297评论 0 0
  • 目录 动态规划与分治法 2.动态规划求解的最优化问题应该具备的两个要素2.1 最优子结构2.2 子问题重叠 动态规...
    王侦阅读 1,440评论 0 1
  • 第八十七章 回到J市的日子忽然就多了一点烟火气,徐艾每天都能接到来自刘辉并不打扰的问候,他不会固定在某一个时刻打给...
    chief风阅读 341评论 3 5