<该文仅供自己学习记录使用>
动 态 规 划
最优化问题就是要找出一个具有最优值(最大或最小)的解。
动态规划通常是用来求解最优化问题的有效方法之一。但并不是所有的最优化问题都可以用动态规划求解。
动态规划与分治策略
动态规划类似于分治策略来求解最优化问题:将规模较大的最优化问题划分成若干规模较小的子问题,然后求出子问题的最优解,最后利用子问题的最优解来构造出原问题的最优解。
动态规划方法与分治法的区别
分治法在求解问题的过程中,将问题划分成若干个子问题,如果子问题还不能求解则继续划分直到子问题规模足够小容易于求解为止。然后再自底向上依次求解子问题并对子问题的解合并得到规模较大问题的解。但每次划分所得的子问题都被求解,而不管子问题是否已重复求解。
动态规划对不同的子问题只求解一次,并将子问题的解保存在表中,下次遇到相同的子问题只需进行查表从而避免对子问题重复求解。这样往往使得计算时间大大缩短。
动态规划方法的基本步骤:
- 说明问题的最优解具有最优子结构特征;
- 把问题最优解的值用子问题最优解的值递归表示;
- 自底向上计算最优解的值 ,并保存各子问题最优解的值及用于构造最优解的信息;
从保存的信息构造一个最优解。
什么是最优子结构特征?
最优子结构特征是指最优化问题的最优解可以由子问题的最优解组合得到。
如何划分子问题?
分析所求的最优化问题最优解的结构;
子问题类型与原问题相同;
说明原问题的最优解具有最优子结构特征;
原问题最优解的值用子问题最优解的值递归表示。
最优子结构
最优子结构是指问题的一个最优解中包含了其子问题的最优解。在动态规划中,每次采用子问题的最优解来构造问题的一个最优解。寻找最优子结构,遵循的共同的模式:
(1)问题的一个解可以是做一个选择,得到一个或者多个有待解决的子问题。
(2)假设对一个给定的问题,已知的是一个可以导致最优解的选择,不必关心如何确定这个选择。
(3)在已知这个选择后,要确定哪些子问题会随之发生,如何最好地描述所得到的子问题空间。
(4)利用“剪贴”技术,来证明问题的一个最优解中,使用的子问题的解本身也是最优的。
最优子结构在问题域中以两种方式变化:
(1)有多少个子问题被使用在原问题的一个最优解中。
(2)在决定一个最优解中使用哪些子问题时有多少个选择。
动态规划按照自底向上的策略利用最优子结构,即:首先找到子问题的最优解,解决子问题,然后逐步向上找到问题的一个最优解。为了描述子问题空间,可以遵循这样一条有效的经验规则,就是尽量保持这个空间简单,然后在需要时再扩充它。
注意:在不能应用最优子结构的时候,就一定不能假设它能够应用。 警惕使用动态规划去解决缺乏最优子结构的问题!
使用动态规划时,子问题之间必须是相互独立的!可以这样理解,N个子问题域互不相干,属于完全不同的空间。
2)重叠子问题
用来解决原问题的递归算法可以反复地解同样的子问题,而不是总是产生新的子问题。重叠子问题是指当一个递归算法不断地调用同一个问题。动态规划算法总是充分利用重叠子问题,通过每个子问题只解一次,把解保存在一个需要时就可以查看的表中,每次查表的时间为常数。
3、总结
动态规划的核心就是找到问题的最优子结构,在找到最优子结构之后的消除重复子问题。最终无论是采用动态规划的自底向上的递推,还是备忘录,或者是备忘录的变型,都可以轻松的找出最优解的构造过程。
4、思考
使用动态规划首先确定解决的问题是否具有最优子结构,那么随之而来的是,什么是最优子结构?
最优子结构就是说,原问题的最优解也是子问题的最优解,
那么什么样的问题,不满足最优子结构呢?
有一个网友给出的例子;
给定一个n*m的矩阵,每个格子里有一个正整数,从左上角开始到右下角,每次只能向下或向右走,问经过的数之和模k后最大能是多少?
定义状态f(i,j)表示从左上角走到i,j的最优解(这里最优解指经过的数之和模k最大),显然从f(i,j)转移到f(i+1,j)或f(i,j+1)显然是不对的。 也就是说,这里一个问题的最优解不一定包含其子问题的最优解,所以不满足最优子结构。。
动态规划求解矩阵链乘积问题
考虑n个矩阵的乘积:A1A2…An,确定最优的乘法顺序(最优括号化方案),使得标量(数值)乘法次数最少。其中,Ai为 pi-1⨯pi矩阵,i=1,2,…,n。
4个矩阵相乘A1A2A3A4的所有乘法顺序:
A1((A2A3)A4) A1(A2(A3A4)) (A1A2)(A3A4) ((A1A2)A3)A4 (A1(A2A3))A4
对于不同的惩罚顺序所花费的时间不同,如何找出最优乘法顺序?
暴力搜索方法确定最优乘法顺序
因此为 n较大时,耗时巨大,计算上不可行!
动态规划方法确定最优乘法顺序
假设n个矩阵连乘A1A2…An的最优乘法顺序中从k0位置将矩阵链分成两段(A1…Ak0)(Ak0+1…An)
记 表示最优乘法顺序需要的标量乘法次数,则:
m[1,n]= m[1,k0]+m[k0,n]+p0pk0pn
可见,为了找最优分割点, 将n个矩阵链分为两部分(A1…AK)(AK+1…An),我们需要考虑
分割位置k的所有可能情况k=1,2,…,n-1,然后从这n-1种可能中选择最好的一种。分别对A1…AK和AK+1…An,进行同样的计算,最后我们就可以求得最优的乘法顺序。
因此,最优乘法顺序具有最优子结构特征!
一般地,确定Ai…Aj (记为Ai…j)的最优乘法顺序时,
令 m[i,j] 表示Ai…Aj所需的最少标量乘法次数,
s[i,j]=arg{k: m[i,j]=m[i,k]+m[k+1,j]+pi-1pkpj}
The time complexity is 。原因是子问题重复求解。利用递归算法直接计算子问题最优解的值,一般需要指数时间,使得实际应用不可行。
最长公共子序列问题
定义1 给定序列X=x1, x2, … xm,在序列X中去掉若干个字符所剩余的部分称为序
列X的子序列。
序列:X=a, b, 1, 2, g, a, t, 4, 6, b
子序列: a, b, g, a, t, b
序列前缀
定义2 序列X=x1 x2 … xm 的前缀Xi=x1 x2 … xi 的i=0,1,…,m。
X1=x1, X2=x1x2, …, Xm=x1x2…xm=X。
序列:X=a, b, 1, 2, g, a, t, 4, 6, b
X0=∅ X1=a X2=ab X3=ab1 X6=ab12ga……
最长公共子序列(LCS)
定义3 序列X=x1 x2 … xm,Y=y1 y2 … yn的所有公共子序列中长度最长的子序列称为X,Y的最长公共子序列,记为LCS(X,Y)。
序列X=x1 x2 … xm,Y=y1 y2 … yn定义c[i,j] 为 Xi 和 Yj 的LCS长度;则X 和 Y 的LCS 的长度为c[m,n]。
最长公共子序列例子
X= {A B C B D A B }, Y= {B D C A B A}
最长公共子序列:
X = A B C B D A B
Y = B D C A B A
LCS是否唯一?
X= {A B C B D A B }, Y= {B D C A B A} 最长公共子序列:
X = A B C B D A B,Y =B D C A B A
LCS(X,Y): BCBA BCAB BDAB
最长公共子序列可以不只一个!
最长公共子序列(LCS)的应用
衡量两个DNA序列的相似程度;
两篇论文相似度的计算。
可以通过计算它们的最长公共子序列s,
将S的长度看成两个串的相近程度.
暴力搜索方法求最长公共子序列(LCS) 至少需要指数时间:Ω(2^m n)
原笔记地址
https://note.youdao.com/ynoteshare1/index.html?id=90c4057fdcaec1c7b58d8f1d558607f3&type=notebook#/D5956EB864C74931975C598A185EE71F