算法导论笔记——第十五章 动态规划

通常用来解决最优化问题。在做出每个选择的同时,通常会生成与原问题形式相同的子问题。当多于一个选择子集都生成相同的子问题时,动态规划技术通常就会非常有效。其关键技术就是对每个这样的子问题都保存其解,当其重复出现时即可避免重复求解。

  分治:划分为互不相交的子问题,递归求解子问题,再将他们的解组合起来。

  动态规划(dynamic programming,表格法而非编程)用于子问题重叠的情况。

四个步骤来设计一个动态规划算法:

  1 刻画一个最优解的结构特征

  2 递归地定义最优解的值

  3 计算最优解的值,通常采用自底向上的方法

  4 利用计算出来的信息构造一个最优解

最优子结构:问题的最优解由相关子问题的最优解组合而成,而这些子问题可以独立求解。

实现方法

带备忘的自顶向下法(top-down with memoization)

自底向上法(bottom-up method), 复杂度系数更小。

15.3 动态规划原理

适合应用动态规划方法求解的最优化问题应具备的两个要素:最优子结构子问题重叠

发掘最优子结构的通用模式:

做出一个选择。它会产生一个或多个待解的子问题。

在可能的第一步选择中,假定已经知道哪种选择会得到最优解

确定这次选择会产生哪些子问题,以及如何最好的刻画子问题空间

每个子问题的解就是它本身的最优解。

一个刻画子问题空间的好经验:保持子问题空间尽可能简单,只有必要时才扩展它。

对于不同问题领域,最优子结构的不同体现在两个方面:最优解用到的子问题总数和确定最优选择时需要考察多少种选择。

可用其乘积来粗略分析运行时间。

子问题必须无关(最长简单路径问题就不能使用动态规划)。如果求解一个子问题用到了某些资源,导致这些资源在求解其他子问题时不可用,则不能动态规划。

如果每个子问题都必须至少求解一次:自底向上

如果子问题空间的某些子问题完全不必求解:自顶向下(递归方式+备忘录)

15.4 最长公共子序列(LCS)

一个给定序列的子序列,就是将给定序列中零个或多个元素去掉之后得到的结果。即不要求连续,故不同于子串,但类似于模糊匹配中的*。

定理15.1(LCS的最优子结构) 令X=<x1,x2,...,xm>,Y=<y1,y2,...,yn>为两个序列,Z=<z1,z2,...,zk>为X和Y的任意LCS。

1. 如果xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的一个LCS。

2. 如果xm!=yn,则zk!=xm意味着Zk-1是Xm-1和Y的一个LCS。

3. 如果xm!=yn,则zk!=yn意味着Zk-1是X和Yn-1的一个LCS。

可以用m*n的数组或者约max(m,n)+O(1)的空间来查找到LCS的长度。如需重构,为了保证O(m+n)的重构时间,则大约需要m*n空间。

15.5 最优二叉搜索树

形式化定义:给定一个n个不同关键字的已排序的序列K=<k1,k2,...,kn>(因此k1<k2<...<kn),我们希望用这些关键字构造一棵二叉树。对每个关键字ki,都有一个概率pi表示其搜索概率。n个关键字及n+1个不存在的伪关键字都带搜索概率。搜索代价最小的二叉搜索树,叫做最优二叉搜索树。

不一定是高度最矮的,概率最高的关键字也不一定出现在二叉搜索树的根结点。

步骤1:最优二叉搜索树的结构

  任意子树包含连续关键字ki,...,kj,叶节点di-1,...,dj(失败搜索)。

  最优子结构:如果一个最优二叉树T有一棵包含关键字ki,...,kj的子树T’,那么T’必然是包含关键字ki,...,kj和伪关键字di-1,...,dj的子问题的最优解。

步骤2:一个递归算法

  注意成为子树后高度增加1

步骤3:计算最优二叉搜索树的期望搜索代价

时间: 2024-10-10 21:06:47

算法导论笔记——第十五章 动态规划的相关文章

算法导论笔记——第十六章 贪心算法

通常用于最优化问题,我们做出一组选择来达到最优解.每步都追求局部最优.对很多问题都能求得最优解,而且速度比动态规划方法快得多. 16.1 活动选择问题 按结束时间排序,然后选择兼容活动. 定理16.1 考虑任意非空子问题Sk,令am是Sk中结束时间最早的活动,则am在Sk的某个最大兼容活动子集中. 16.2 贪心算法原理 设计贪心算法步骤: 1>将最优化问题转化为这样的形式:对其做出一次选择后,只剩下一个子问题需要求解. 2>证明作出贪心选择后,原问题总是存在最优解,即贪心选择总是安全的. 3

算法导论笔记——第十~十一章 数据结构(一) 散列

第十章 基本数据结构 栈:可由数组表示 队列:可由数组表示 指针和对象:可由多数组表示.可用栈表示free list 有根数: 二叉树:左右孩子 分支无限制:左孩子右兄弟表示法 第十一章 散列表 数组:为每个元素保留一个位置 散列表:用于实际存储关键字比全部可能关键字少很多时,比如字典操作 解决散列冲突:链接法,开放寻址法 11.2 散列表 用链表法,在简单均匀散列的假设下,一次成功或不成功的查找所需要的平均时间为Θ(1+α),α为load factor. 11.3 散列函数 好的散列函数应(近

算法导论第十五章动态规划

概述: 1.动态规划是通过组合子问题的解而解决原问题的. 2.动态规划适用于子问题不是独立的情况,也就是各子问题的包含公共的子子问题. 3.动态规划对每个子问题只求解一次,将其结果保存在一张表中. 4.动态规划的设计步骤:a.描述最优解的结构b.递归定义最优解的值c.按自底向上的方式计算最优觖的值d.由计算出的结构构造一个最优解 15.1钢条切割 钢条切割问题:给定定长的钢条和价格表,求切割方案,使得收益最大.如果n英寸的钢条的价格足够大,则不需要切割. 代码如下: //朴素递归求解钢条切割收益

算法导论基础(第一~五章)

插入排序 最好情况输入数组开始时候就是满足要求的排好序的,时间代价为θ(n): 最坏情况输入数组是按逆序排序的,时间代价为θ(n^2). 归并排序 归并排序采用了算法设计中的分治法,分治法的思想是将原问题分解成n个规模较小而结构与原问题相似的小问题,递归的解决这些子问题,然后再去合并其结果,得到原问题的解. 分治模式在每一层递归上有三个步骤: 分解(divide):将原问题分解成一系列子问题. 解决(conquer):递归地解答各子问题,若子问题足够小,则直接求解. 合并(combine):将子

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

动态规划 注:该篇为本人原创,转载请注明出处:http://blog.csdn.net/chudongfang2015/article/details/51590817--开心 -.- 个人对动态规划的理解: 1.动态规划是一个付出额外空间来节省时间,就是所谓的空间换时间. 2.动态规划储存每个状态的最优解. 3.动态规划是用来把子问题的结果储存下来,再次用到的时候就不必再进行重复计算. 算法导论对动态规划的解释: 动态规划和分治方法相似,都是通过组合子问题的解来求解原问题,分治方法将问题划分为

算法导论笔记——第十二~十四章 数据结构(二)树

第十二章 二叉搜索树 >=左子树的所有key,<=右子树的所有key 在一棵高度为h的二叉搜索树上,动态集合上的操作SEARCH,MINIMUM,MAXIMUM,SUCCESSOR,PREDECESSOR,INSERT和DELETE可以在O(h)时间内完成. h>=(lgn向下取整) 和快速排序算法一样,其平均性能更接近于最好情形. 随机构建二叉搜索树期望高度为O(lgn). 各种操作请自行查阅. 第十三章 红黑树 是一种(近似)平衡的二叉搜索树.可以保证在最坏情况下基本动态集合操作的时

第十五章 动态规划——钢条切割

前言:动态规划的概念 动态规划(dynamic programming)是通过组合子问题的解而解决整个问题的.分治算法是指将问题划分为一些独立的子问题,递归的求解各个问题,然后合并子问题的解而得到原问题的解.例如归并排序,快速排序都是采用分治算法思想.本书在第二章介绍归并排序时,详细介绍了分治算法的操作步骤,详细的内容请参考:http://www.cnblogs.com/Anker/archive/2013/01/22/2871042.html.而动态规划与此不同,适用于子问题不是独立的情况,也

C++实现算法导论十五章动态规划之钢条分割问题

#include<iostream> #include<algorithm> #include<utility> #include<vector> using namespace std; //采用普通的递归算法来求解钢条分割的最大的收益 int cut_rod(int *p,const int &n) { if(n==0) return 0; int q=-1; for(int i=1;i<=n;++i) { q=max(q,p[i]+cut

第十五章 动态规划——矩阵链乘法

前言:今天接着学习动态规划算法,学习如何用动态规划来分析解决矩阵链乘问题.首先回顾一下矩阵乘法运算法,并给出C++语言实现过程.然后采用动态规划算法分析矩阵链乘问题并给出C语言实现过程. 1.矩阵乘法 从定义可以看出:只有当矩阵A的列数与矩阵B的行数相等时A×B才有意义.一个m×r的矩阵A左乘一个r×n的矩阵B,会得到一个m×n的矩阵C.在计算机中,一个矩阵说穿了就是一个二维数组.一个m行r列的矩阵可以乘以一个r行n列的矩阵,得到的结果是一个m行n列的矩阵,其中的第i行第j列位置上的数等于前一个