动态规划笔记.docx
《动态规划笔记.docx》由会员分享,可在线阅读,更多相关《动态规划笔记.docx(21页珍藏版)》请在冰豆网上搜索。
![动态规划笔记.docx](https://file1.bdocx.com/fileroot1/2023-2/6/27345240-2255-4011-8f5b-8ec9d130e219/27345240-2255-4011-8f5b-8ec9d130e2191.gif)
动态规划笔记
算法总体思想
动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题
但是经分解得到的子问题往往不是互相独立的。
不同子问题的数目常常只有多项式量级。
在用分治法求解时,有些子问题被重复计算了许多次。
如果能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,就可以避免大量重复计算,从而得到多项式时间算法。
动态规划基本步骤
⏹找出最优解的性质,并刻划其结构特征。
⏹递归地定义最优值。
⏹以自底向上的方式计算出最优值。
⏹根据计算最优值时得到的信息,构造最优解。
完全加括号的矩阵连乘积
16000,10500,36000,87500,34500
矩阵连乘问题
给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2…,n-1。
如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。
◆穷举法:
列举出所有可能的计算次序,并计算出每一种计算次序相应需要的数乘次数,从中找出一种数乘次数最少的计算次序。
◆算法复杂度分析:
◆对于n个矩阵的连乘积,设其不同的计算次序为P(n)。
◆由于每种加括号方式都可以分解为两个子矩阵的加括号问题:
(A1...Ak)(Ak+1…An)可以得到关于P(n)的递推式如下:
◆动态规划
◆将矩阵连乘积
简记为A[i:
j],这里i≤j
◆考察计算A[i:
j]的最优计算次序。
设这个计算次序在矩阵Ak和Ak+1之间将矩阵链断开,i≤k◆计算量:
A[i:
k]的计算量加上A[k+1:
j]的计算量,再加上A[i:
k]和A[k+1:
j]相乘的计算量
分析最优解的结构
特征:
计算A[i:
j]的最优次序所包含的计算矩阵子链A[i:
k]和A[k+1:
j]的次序也是最优的。
矩阵连乘计算次序问题的最优解包含着其子问题的最优解。
这种性质称为最优子结构性质。
问题的最优子结构性质是该问题可用动态规划算法求解的显著特征。
建立递归关系
设计算A[i:
j],1≤i≤j≤n,所需要的最少数乘次数m[i,j],则原问题的最优值为m[1,n]
当i=j时,A[i:
j]=Ai,因此,m[i,i]=0,i=1,2,…,n
当i;这里
的维数为
可以递归地定义m[i,j]为:
的位置只有
种可能
计算最优值
对于1≤i≤j≤n不同的有序对(i,j)对应于不同的子问题。
因此,不同子问题的个数最多只有
由此可见,在递归计算时,许多子问题被重复计算多次。
这也是该问题可用动态规划算法求解的又一显著特征。
用动态规划算法解此问题,可依据其递归式以自底向上的方式进行计算。
在计算过程中,保存已解决的子问题答案。
每个子问题只计算一次,而在后面需要时只要简单查一下,从而避免大量的重复计算,最终得到多项式时间的算法
用动态规划法求最优解
voidMatrixChain(int*p,intn,int**m,int**s)
{
for(inti=1;i<=n;i++)m[i][i]=0;
for(intr=2;r<=n;r++)
for(inti=1;i<=n-r+1;i++){
intj=i+r-1;
m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j]=i;
for(intk=i+1;kintt=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
if(t}
}
}
算法复杂度分析:
算法matrixChain的主要计算量取决于算法中对r,i和k的3重循环。
循环体内的计算量为O
(1),而3重循环的总次数为O(n3)。
因此算法的计算时间上界为O(n3)。
算法所占用的空间显然为O(n2)。
动态规划算法的基本要素
一、最优子结构
•矩阵连乘计算次序问题的最优解包含着其子问题的最优解。
这种性质称为最优子结构性质。
•在分析问题的最优子结构性质时,所用的方法具有普遍性:
首先假设由问题的最优解导出的子问题的解不是最优的,然后再设法说明在这个假设下可构造出比原问题最优解更好的解,从而导致矛盾。
•利用问题的最优子结构性质,以自底向上的方式递归地从子问题的最优解逐步构造出整个问题的最优解。
最优子结构是问题能用动态规划算法求解的前提。
同一个问题可以有多种方式刻划它的最优子结构,有些表示方法的求解速度更快(空间占用小,问题的维度低)
二、重叠子问题
•递归算法求解问题时,每次产生的子问题并不总是新问题,有些子问题被反复计算多次。
这种性质称为子问题的重叠性质。
•动态规划算法,对每一个子问题只解一次,而后将其解保存在一个表格中,当再次需要解此子问题时,只是简单地用常数时间查看一下结果。
•通常不同的子问题个数随问题的大小呈多项式增长。
因此用动态规划算法只需要多项式时间,从而获得较高的解题效率。
三、备忘录方法
•备忘录方法的控制结构与直接递归方法的控制结构相同,区别在于备忘录方法为每个解过的子问题建立了备忘录以备需要时查看,避免了相同子问题的重复求解。
intLookupChain(inti,intj)
{
if(m[i][j]>0)returnm[i][j];
if(i==j)return0;
intu=LookupChain(i,i)+LookupChain(i+1,j)+p[i-1]*p[i]*p[j];
s[i][j]=i;
for(intk=i+1;kintt=LookupChain(i,k)+LookupChain(k+1,j)+p[i-1]*p[k]*p[j];
if(t
}
m[i][j]=u;
returnu;
}
最长公共子序列
•若给定序列X={x1,x2,…,xm},则另一序列Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:
zj=xij。
例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。
•给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
•给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找出X和Y的最长公共子序列。
设序列X={x1,x2,…,xm}和Y={y1,y2,…,yn}的最长公共子序列为Z={z1,z2,…,zk},则
(1)若xm=yn,则zk=xm=yn,且zk-1是xm-1和yn-1的最长公共子序列。
(2)若xm≠yn且zk≠xm,则Z是xm-1和Y的最长公共子序列。
(3)若xm≠yn且zk≠yn,则Z是X和yn-1的最长公共子序列。
由此可见,2个序列的最长公共子序列包含了这2个序列的前缀的最长公共子序列。
因此,最长公共子序列问题具有最优子结构性质。
子问题的递归结构
由最长公共子序列问题的最优子结构性质建立子问题最优值的递归关系。
用c[i][j]记录序列和的最长公共子序列的长度。
其中,Xi={x1,x2,…,xi};Yj={y1,y2,…,yj}。
当i=0或j=0时,空序列是Xi和Yj的最长公共子序列。
故此时C[i][j]=0。
其它情况下,由最优子结构性质可建立递归关系如下:
计算最优值
由于在所考虑的子问题空间中,总共有θ(mn)个不同的子问题,因此,用动态规划算法自底向上地计算最优值能提高算法的效率。
voidLCSLength(intm,intn,char*x,char*y,int**c,int**b)
{
inti,j;
for(i=1;i<=m;i++)c[i][0]=0;
for(i=1;i<=n;i++)c[0][i]=0;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++){
if(x[i]==y[j]){
c[i][j]=c[i-1][j-1]+1;b[i][j]=1;}
elseif(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;}
}
}
构造最长公共子序列
voidLCS(inti,intj,char*x,int**b)
{
if(i==0||j==0)return;
if(b[i][j]==1){LCS(i-1,j-1,x,b);cout<elseif(b[i][j]==2)LCS(i-1,j,x,b);
elseLCS(i,j-1,x,b);
}
算法的改进
•在算法lcsLength和lcs中,可进一步将数组b省去。
事实上,数组元素c[i][j]的值仅由c[i-1][j-1],c[i-1][j]和c[i][j-1]这3个数组元素的值所确定。
对于给定的数组元素c[i][j],可以不借助于数组b而仅借助于c本身在时间内确定c[i][j]的值是由c[i-1][j-1],c[i-1][j]和c[i][j-1]中哪一个值所确定的。
•如果只需要计算最长公共子序列的长度,则算法的空间需求可大大减少。
事实上,在计算c[i][j]时,只用到数组c的第i行和第i-1行。
因此,用2行的数组空间就可以计算出最长公共子序列的长度。
进一步的分析还可将空间需求减至O(min(m,n))。
凸多边形最优三角剖分
•用多边形顶点的逆时针序列表示凸多边形,即P={v0,v1,…,vn-1}表示具有n条边的凸多边形。
•若vi与vj是多边形上不相邻的2个顶点,则线段vivj称为多边形的一条弦。
弦将多边形分割成2个多边形{vi,vi+1,…,vj}和{vj,vj+1,…vi}。
•多边形的三角剖分是将多边形分割成互不相交的三角形的弦的集合T。
•给定凸多边形P,以及定义在由多边形的边和弦组成的三角形上的权函数w。
要求确定该凸多边形的三角剖分,使得即该三角剖分中诸三角形上权之和为最小。
三角剖分的结构及其相关问题
•一个表达式的完全加括号方式相应于一棵完全二叉树,称为表达式的语法树。
例如,完全加括号的矩阵连乘积((A1(A2A3))(A4(A5A6)))所相应的语法树如图(a)所示。
•凸多边形{v0,v1,…vn-1}的三角剖分也可以用语法树表示。
例如,图(b)中凸多边形的三角剖分可用图(a)所示的语法树表示。
•矩阵连乘积中的每个矩阵Ai对应于凸(n+1)边形中的一条边vi-1vi。
三角剖分中的一条弦vivj,ij]。
最优子结构性质
•凸多边形的最优三角剖分问题有最优子结构性质。
•事实上,若凸(n+1)边形P={v0,v1,…,vn-1}的最优三角剖分T包含三角形v0vkvn,1≤k≤n-1,则T的权为3个部分权的和:
三角形v0vkvn的权,子多边形{v0,v1,…,vk}和{vk,vk+1,…,vn}的权之和。
可以断言,由T所确定的这2个子多边形的三角剖分也是最优的。
因为若有{v0,v1,…,vk}或{vk,vk+1,…,vn}的更小权的三角剖分将导致T不是最优三角剖分的矛盾。
最优三角剖分的递归结构
•定义t[i][j],1≤i为方便起见,设退化的多边形{vi-1,vi}具有权值0。
据此定义,要计算的凸(n+1)边形P的最优权值为t[1][n]。
•t[i][j]的值可以利用最优子结构性质递归地计算。
当j-i≥1时,凸子多边形至少有3个顶点。
由最优子结构性质,t[i][j]的值应为t[i][k]的值加上t[k+1][j]的值,再加上三角形vi-1vkvj的权值,其中i≤k≤j-1。
由于在计算时还不知道k的确切位置,而k的所有可能位置只有j-i个,因此可以在这j-i个位置中选出使t[i][j]值达到最小的位置。
由此,t[i][j]可递归地定义为:
多边形游戏
多边形游戏是一个单人玩的游戏,开始时有一个由n个顶点构成的多边形。
每个顶点被赋予一个整数值,每条边被赋予一个运算符“+”或“*”。
所有边依次用整数从1到n编号。
游戏第1步,将一条边删除。
随后n-1步按以下方式操作:
(1)选择一条边E以及由E连接着的2个顶点V1和V2;
(2)用一个新的顶点取代边E以及由E连接着的2个顶点V1和V2。
将由顶点V1和V2的整数值通过边E上的运算得到的结果赋予新顶点。
最后,所有边都被删除,游戏结束。
游戏的得分就是所剩顶点上的整数值。
问题:
对于给定的多边形,计算最高得分。
最优子结构性质
•在所给多边形中,从顶点i(1≤i≤n)开始,长度为j(链中有j个顶点)的顺时针链p(i,j)可表示为v[i],op[i+1],…,v[i+j-1]。
•如果这条链的最后一次合并运算在op[i+s]处发生(1≤s≤j-1),则可在op[i+s]处将链分割为2个子链p(i,s)和p(i+s,j-s)。
•设m1是对子链p(i,s)的任意一种合并方式得到的值,而a和b分别是在所有可能的合并中得到的最小值和最大值。
m2是p(i+s,j-s)的任意一种合并方式得到的值,而c和d分别是在所有可能的合并中得到的最小值和最大值。
依此定义有a≤m1≤b,c≤m2≤d
(1)当op[i+s]='+'时,显然有a+c≤m≤b+d
(2)当op[i+s]='*'时,有min{ac,ad,bc,bd}≤m≤max{ac,ad,bc,bd}
•换句话说,主链的最大值和最小值可由子链的最大值和最小值得到。
图像压缩
图象的变位压缩存储格式将所给的象素点序列{p1,p2,…,pn},0≤pi≤255分割成m个连续段S1,S2,…,Sm。
第i个象素段Si中(1≤i≤m),有l[i]个象素,且该段中每个象素都只用b[i]位表示。
设
则第i个象素段Si为
设
,则hib[i]8。
因此需要用3位表示b[i],如果限制1l[i]255,则需要用8位表示l[i]。
因此,第i个象素段所需的存储空间为l[i]*b[i]+11位。
按此格式存储象素序列{p1,p2,…,pn},需要
位的存储空间。
图象压缩问题要求确定象素序列{p1,p2,…,pn}的最优分段,使得依此分段所需的存储空间最少。
每个分段的长度不超过256位。
电路布线
在一块电路板的上、下2端分别有n个接线柱。
根据电路设计,要求用导线(i,π(i))将上端接线柱与下端接线柱相连,如图所示。
其中π(i)是{1,2,…,n}的一个排列。
导线(i,π(i))称为该电路板上的第i条连线。
对于任何1≤iπ(j)。
电路布线问题要确定将哪些连线安排在第一层上,使得该层上有尽可能多的连线。
换句话说,该问题要求确定导线集Nets={(i,π(i)),1≤i≤n}的最大不相交子集。
记
。
N(i,j)的最大不相交子集为MNS(i,j)。
Size(i,j)=|MNS(i,j)|。
(1)当i=1时,
(2)当i>1时,
2.1j<π(i)。
此时,
。
故在这种情况下,N(i,j)=N(i-1,j),从而Size(i,j)=Size(i-1,j)。
2.2j≥π(i),(i,π(i))∈MNS(i,j)。
则对任意(t,π(t))∈MNS(i,j)有t
在这种情况下MNS(i,j)-{(i,π(i))}是N(i-1,π(i)-1)的最大不相交子集。
2.3若
,则对任意(t,π(t))∈MNS(i,j)有
t
从而
。
因此,Size(i,j)≤Size(i-1,j)。
另一方面
,故又有Size(i,j)≥Size(i-1,j),
从而Size(i,j)=Size(i-1,j)。
(1)当i=1时
(2)当i>1时
流水作业调度
n个作业{1,2,…,n}要在由2台机器M1和M2组成的流水线上完成加工。
每个作业加工的顺序都是先在M1上加工,然后在M2上加工。
M1和M2加工作业i所需的时间分别为ai和bi。
流水作业调度问题要求确定这n个作业的最优加工顺序,使得从第一个作业在机器M1上开始加工,到最后一个作业在机器M2上加工完成所需的时间最少。
分析:
•直观上,一个最优调度应使机器M1没有空闲时间,且机器M2的空闲时间最少。
在一般情况下,机器M2上会有机器空闲和作业积压2种情况。
•设全部作业的集合为N={1,2,…,n}。
SN是N的作业子集。
在一般情况下,机器M1开始加工S中作业时,机器M2还在加工其它作业,要等时间t后才可利用。
将这种情况下完成S中作业所需的最短时间记为T(S,t)。
流水作业调度问题的最优值为T(N,0)。
设是所给n个流水作业的一个最优调度,它所需的加工时间为a
(1)+T’。
其中T’是在机器M2的等待时间为b
(1)时,安排作业
(2),…,(n)所需的时间。
记S=N-{
(1)},则有T’=T(S,b
(1))。
证明:
事实上,由T的定义知T’T(S,b
(1))。
若T’>T(S,b
(1)),设’是作业集S在机器M2的等待时间为b
(1)情况下的一个最优调度。
则
(1),’
(2),…,’(n)是N的一个调度,且该调度所需的时间为a
(1)+T(S,b
(1))(1)+T’。
这与是N的最优调度矛盾。
故T’T(S,b
(1))。
从而T’=T(S,b
(1))。
这就证明了流水作业调度问题具有最优子结构的性质。
由流水作业调度问题的最优子结构性质可知,
Johnson不等式
对递归式的深入分析表明,算法可进一步得到简化。
设是作业集S在机器M2的等待时间为t时的任一最优调度。
若
(1)=i,
(2)=j。
则由动态规划递归式可得:
T(S,t)=ai+T(S-{i},bi+max{t-ai,0})=ai+aj+T(S-{i,j},tij)
其中,
如果作业i和j满足min{bi,aj}≥min{bj,ai},则称作业i和j满足Johnson不等式。
流水作业调度的Johnson法则
交换作业i和作业j的加工顺序,得到作业集S的另一调度,它所需的加工时间为T’(S,t)=ai+aj+T(S-{i,j},tji)
其中,
当作业i和j满足Johnson不等式时,有
由此可见当作业i和作业j不满足Johnson不等式时,交换它们的加工顺序后,不增加加工时间。
对于流水作业调度问题,必存在最优调度,使得作业(i)和(i+1)满足Johnson不等式。
进一步还可以证明,调度满足Johnson法则当且仅当对任意i由此可知,所有满足Johnson法则的调度均为最优调度。
流水作业调度问题的Johnson算法
(1)令
(2)将N1中作业依ai的非减序排序;将N2中作业依bi的非增序排序;
(3)N1中作业接N2中作业构成满足Johnson法则的最优调度。
算法复杂度分析:
算法的主要计算时间花在对作业集的排序。
因此,在最坏情况下算法所需的计算时间为O(nlogn)。
所需的空间为O(n)。
0-1背包问题
给定n种物品和一背包。
物品i的重量是wi,其价值为vi,背包的容量为C。
问应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
0-1背包问题是一个特殊的整数规划问题。
设所给0-1背包问题的子问题
算法复杂度分析:
从m(i,j)的递归式容易看出,算法需要O(nc)计算时间。
当背包容量c很大时,算法需要的计算时间较多。
例如,当c>2n时,算法需要Ω(n2n)计算时间。
的最优值为m(i,j),即m(i,j)是背包容量为j,可选择物品为i,i+1,…,n时0-1背包问题的最优值。
由0-1背包问题的最优子结构性质,可以建立计算m(i,j)的递归式如下。
由m(i,j)的递归式容易证明,在一般情况下,对每一个确定的i(1≤i≤n),函数m(i,j)是关于变量j的阶梯状单调不减函数。
跳跃点是这一类函数的描述特征。
在一般情况下,函数m(i,j)由其全部跳跃点唯一确定。
如图所示。
对每一个确定的i(1≤i≤n),用一个表p[i]存储函数m(i,j)的全部跳跃点。
表p[i]可依计算m(i,j)的递归式递归地由表p[i+1]计算,初始时p[n+1]={(0,0)}。
一个例子
n=3,c=6,w={4,3,2},v={5,2,1}。
算法改进
•函数m(i,j)是由函数m(i+1,j)与函数m(i+1,j-wi)+vi作max运算得到的。
因此,函数m(i,j)的全部跳跃点包含于函数m(i+1,j)的跳跃点集p[i+1]与函数m(i+1,j-wi)+vi的跳跃点集q[i+1]的并集中。
易知,(s,t)q[i+1]当且仅当wisc且(s-wi,t-vi)p[i+1]。
因此,容易由p[i+1]确定跳跃点集q[i+1]如下q[i+1]=p[i+1](wi,vi)={(j+wi,m(i,j)+vi)|(j,m(i,j))p[i+1]}
•另一方面,设(a,b)和(c,d)是p[i+1]q[i+1]中的2个跳跃点,则当ca且d
除受控跳跃点外,p[i+1]q[i+1]中的其它跳跃点均为p[i]中的跳跃点。
•由此可见,在递归地由表p[i+1]计算表p[i]时,可先由p[i+1]计算出q[i+1],然后合并表p[i+1]和表q[i+1],并清除其中的受控跳跃点得到表p[i]。
n=5,c=10,w={2,2,6,5,4},v={6,3,5,4,6}。
初始时p[6]={(0,0)},(w5,v5)=(4,6)。
因此,q[6]=p[6](w5,v5)={(4,6)}。
p[5]={(0,0),(4,6)}。
q[5]=p[5](w4,v4)={(5,4),(9,10)}。
从跳跃点集p[5]与q[5]的并集p[5]q[5]={(0,0),(4,6),(5,4),(9,10)}中看到跳跃点(5,4)受控于跳跃点(4,6)。
将受控跳跃点(5,4)清除后,得到p[4]={(0,0),(4,6),(9,10)}
q[4]=p[4](6,5)={(6,5),(10,11)}
p[3]={(0,0),(4,6),(9,10),(10,11)}
q[3]=p[3](2,3)={(2,3),(6,9)}
p[2]={(0,0),(2,3),(4,6),(6,9),(9,10),(10,11)}
q[2]=p[2](2,6)={(2,6),(4,9),(6,12),(8,15)}
p[1]={(0,0),(2,6),(4,9),(6,12),(8,15)}
p[1]的最后的那个跳跃点(8,15)给出所求的