美文网首页数据结构与算法
算法导论学习笔记(六):动态规划

算法导论学习笔记(六):动态规划

作者: yoshino | 来源:发表于2017-04-17 17:26 被阅读73次

转载请注明原作者 @yoshino,强烈要求简书支持TOC目录和数学公式的输入!
更新不及时,有空慢慢写吧,原文是写在Bear上粘贴来简书的,可能格式有点乱。
具体的工程在我的github上。


动态规划(dynamic programming,DP),与分治策略相似,通过求解子问题来求解原问题,不同于分治策略的事DP的子问题是相互重叠的,DP通常是用来求解最优化问题,设计一个动态规划算法步骤:

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

钢条切割

钢条切割问题描述

求解思路

对于一根程度为l的钢条,有两种不同的切割法:

  • 不切割:此时的收益为rl=pl
  • 切割成长度i和l-i两部分:此时收益用递归表示:rl=ri+l-i
    最大收益可以写成:p=max(pl,ri+l-i,…,r1+l-1)
    即取其中最大的

两种动态规划算法:

  • 带备忘的自顶向下算法:按照自然递归的形式编写过程,过程中保留之前子问题的解,其中会检查是否已经保过此解,如果已经保存了就直接返回保存的值,从而节省了计算的时间。
    public int memoizedCutRodAux(int price[], int r[], int l) {//带备忘的自顶向下法
        if (r[l] > 0) {
            return r[l];//r[l]用来存储当长度为l时的最优解,price用来存储题目给出的收益值
        } else {
            int profit = 0;
            for (int i = 1; i <= l; i++) {
                profit=Math.max(profit,price[i]+memoizedCutRodAux(price,r,l-i));
            }
            r[l]=profit;//保存最优解
            return profit;
        }
    }
  • 自底向上法:任何子问题的求解都依赖于更小子问题的求解,把子问题按照规模大小进行排序,按从大到小的顺序进行求解,这样求解时保证每个求解的问题的前提子问题都已经求解过了
public int bottomUpCutRod(int price[], int r[], int l) {
        for (int i = 1; i <= l; i++) {
            int profit = 0;
            for (int j = 1; j <= i; j++) {
                profit = Math.max(profit, price[j] + r[i - j]);
            }
            r[i] = profit;
        }
        return r[l];
    }

最长公共子序列(longest-common-subsequence,LCS)

问题描述

给定两个公共子序列X=<A,B,C,B,D,A,B>和Y=<B,D,C,A,B,A>,求X Y的长度最长的公共子序列,子序列不要求要连续,但是顺序要相同

问题分析

  1. 刻画LCS特征,定义前缀对:


    前缀对

    从定理15.1可以得出,两个序列的LCS包含两个序列的前缀的LCS。

  2. 得出一个递归解
    从定理15.1可以知道:
  • 若xm=yn,则求解Xm-1和Yn-1的LCS,将xm=yn至于后面即可
  • 若xm不等于yn,则求解Xm-1和Yn的LCS和Xm和Yn-1的LCS,取其中较长的作为LCS
    之所以能做这样的假设,是因为最优解必然出现在X和Y中。
    LCS递归公式
  1. 计算LCS的长度
  • 建立一个矩阵c[0...m,0...n]用来保存c[i,j]的值
  • 建立一个表b[1...m,1...n]用来保存最优解,即b[i,j]保存c[i,j]的子问题最优解
  • java代码实现
private int[][] LCSLength(String[] X, String[] Y) {
        ArrayList<ArrayList> result = new ArrayList<ArrayList>();
        int m = X.length;
        int n = Y.length;
        int[][] c = new int[m + 1][n + 1];
        int[][] b = new int[m + 1][n + 1];
        for (int i = 1; i < m; i++)
            for (int j = 0; j < n + 1; j++) {
                c[i][j] = 0;
            }
        for (int i = 1; i <= m; i++)
            for (int j = 1; j <= n; j++) {
                if (X[i - 1] == Y[j - 1]) {//为了照顾c的序号,所以所有的X,Y均-1了
                    c[i][j] = c[i - 1][j - 1] + 1;
                    b[i][j] = 1;//代表左上箭头
                } else if (c[i - 1][j] >= c[i][j - 1]) {
                    c[i][j] = c[i - 1][j];
                    b[i][j] = 2;//代表向上箭头
                } else {
                    c[i][j] = c[i][j - 1];
                    b[i][j] = 3;//代表向左箭头
                }
            }
        return b;
    }
  1. 构造LCS
    从第三步我们得到的b[i,j],我们得到了构造LCS的方向,递归回溯打印LCS即可
    private void printLCS(int[][] b, String[] X, int i, int j) {
        if (i != 0 && j != 0) {
            if (b[i][j] == 1) {
                printLCS(b, X, i - 1, j - 1);
                System.out.print(X[i-1]);
            } else if (b[i][j] == 2) {
                printLCS(b, X, i - 1, j);
            } else {
                printLCS(b, X, i, j - 1);
            }
        }
    }

最优二叉搜索树

问题描述

给定一个n个不同关键字的已排序的序列K=<k1,k2,...,kn>(递增序列),对于每个关键字ki,都有一个概率pi表示其搜索频率。当然有些搜索的值可能不在K中,所以我们给出n+1个伪关键字“d0,d1,…,dn”,其中d0表示所有小于k1的值,dn表示所有大于kn的值,对于每个di,也有相应的概率pi

相关文章

  • 算法导论学习笔记(六):动态规划

    转载请注明原作者 @yoshino,强烈要求简书支持TOC目录和数学公式的输入!更新不及时,有空慢慢写吧,原文是写...

  • 算法导论动态规划笔记

    动态规划通常用于求解最优化问题与分治方法不同,动态规划应用于子问题重叠的情况,通过保存中间解,避免重复计算同样的子...

  • 动态规划、贪心算法区别

    本文整理自MIT算法导论公开课 1. 动态规划(Dynamic progamming) 动态规划是一种设计技巧,...

  • 《算法导论》--动态规划

    1. 概述 动态规划与分治法相似,都是通过组合子问题来求解原问题。区别在于,分治法将问题划分为互不相交的子问题,递...

  • 算法导论-动态规划

    https://blog.csdn.net/gqtcgq/article/details/45530443[htt...

  • 带你入门动态规划算法

    一、导论  动态规划(Dynamic Programming,DP)是算法设计思想中最难也是最有趣的部分。掌握动态...

  • 最长公共子序列

    最长公共子序列是一个很经典的动态规划问题,最近正在学习动态规划,所以拿来这里再整理一下。 这个问题在《算法导论》中...

  • 最长公共子序列

    最长公共子序列是一个很经典的动态规划问题,最近正在学习动态规划,所以拿来这里再整理一下。这个问题在《算法导论》中作...

  • 斐波那契数(递归/剪枝/迭代)

    算法学习笔记,参考于动态规划进阶讲解[https://labuladong.github.io/algo/%E5%...

  • 4. 动态规划算法

    1. 动态规划算法总结2. 漫画:什么是动态规划?3.算法之动态规划4. 动态规划-算法

网友评论

    本文标题:算法导论学习笔记(六):动态规划

    本文链接:https://www.haomeiwen.com/subject/ltotzttx.html