第一小节 动态规划问题
——最短路径问题
一 在正式提出动态规划法前我们先看一个数学例子:
例 1 :在 x +x2 +x3 +…+xn =a 是约束条件下, 求 的极大值 .
令 ( 0 )
令 且
可得 a - x=x, 所以 x=a/2
故
同理
令
所以 a - x=2x , x=a/3
所以 f3 (a)=
用数学归纳法可以证明: fn (a) = , x1 =x2 =x3 =…=xn =
证明: 1 : n=1 …
2 :设 fn (a) = , x1 =x2 =x3 =…=xn = 成立,则
fn+1 (a)=max( +fn (a-x))=max( )
令 y=
y’= =
所以 nx=a-x ,(n+1)x=a
x=
fn+1 (a)= +n =
我们刚才的解题策略是:“摸着石头过河”, f2 利用 f1 的结果, f3 又利用 f2 的结果。。。。。。类似于游戏中的一个勇士打败了一些敌人后得到一件武器,然后去打败另一个强大一些的对手,得到一件更好的武器,接着打败更强大的敌人。。。。。最后取得胜利。。。
在实际生活中,有这么一类问题,它们的活动过程可分为若干个阶段,而且在任一阶段 后的行为仅依赖于第 I 阶段的过程状态,而与 I 阶段之前的过程如何达到这种过程如何达到这种状态的方式无关,这样的过程就构成了一个多阶段决策过程。在 50 年代,贝尔曼( Richard Bellman )等人根据这类问题的多阶段决策的特性,提出了解决问题的“最优性原理”从而创建了最优化问题的一种最新的算法设计方法——动态规划。
分治法和动态规划法的比较
动态规划算法与分治法类似,其根本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解,与分治法不同的是,适合于用动态规划法求解的问题,经分解得到的子问题往往不是互相独立的 . 以从 16 个数据中找出最大者为例,说明 分治法的“静”和动态规划法的“动”的区别。
下面我们以具体的例子来说明如何运用动态规划算法来求解问题,并分析可用动态规划算法解的问题的所应具备的一般特征。
对教材 68 页上的里子给予简要说明(因为书上的文字叙述有些含混晦涩,对符号的说明不清晰)
y
2 K 3 P 1 S 2 U
下面精讲一个例子 2 1 2 2 3
|
3 4 1 2 3
D H M R
2 2 1 3 4
3 2 3
1. 介绍这个图的特点 ….. 从而说明从 O 到 A 的最短路径必由 7 段而不是更多或更少段组成。其行进路线必然是 x 和 y 单调递增的(非严格单调)。从 O(0,0) 到 U ( 4 , 3 )点的每一条路径对应于由 4 个 x 上的和 3 个 y 上的字符构成的字符串,这种字符串的数目为 C =35. 如果采用穷举法进行搜索,需要进行 35*6=210 次加法, 34 次比较。
2. 下面我们采用动态规划法来解决这一问题。令 O 为起点到 U 的最短距离为 Do ,以 A 为起点到 U 的最短距离为 DA - - - , 用 dij 表示( i , j )边的长度。 显然 Ds=dsu=2,Dt=dTU=3,
DQ =min{2+2,5+3}=4
DP =1+Ds=1+2=3
DR =3+DT =3+3=6
DL =min{Dlq+DQ,dLP +DP}=min{4+DQ ,2+Dp}=min{4+4,2+3}=5
Dk=3+Dp=3+3=6
DM = min{2+DQ ,4+DR }=min{2+4,4+6}=6
DN =4+DR =4+6=10
DF =2+DK =2+6=8
DG =min{1+DK ,3+DL }=min{1+6,3+5}=7
DH =min{1+5,1+6}=6
DJ =min{3+DM ,3+DN }=min{3+6,3+10}=9
DC =min{2+DF ,2+DG }=min{2+8,2+7}=9
DD =min{4+DG ,2+DH }=min{4+7,2+6}=8
DE =min{1+DH ,2+DJ }=min{1+6,2+9}=7
DA =min{3+DC , 2+DD }=min{3+9,2+8}=10
DB =min{2+DD ,3+DE }==min{2+8,3+7}=10
Do==min{1+DB ,2+DA }=min{1+10,2+10}=11
共进行了 29 次加法, 12 次比较。由 Do=1+DB=11 回溯,可得到最短路径为
O—>B- à D->H à L—>P- à S- à U
O- à B- à E- à H- à L- à P- à S- à U
推广到 x 轴 m 段 y 轴 n 段的情形:用动态规划法需要做 2mn+ ( m+n-2 )次加法, mm 次比较;而如果用穷举法,需要 次加法, 次比较。
若 m=n, 动态规划法要做 2n2 +2n-2 次加法, n2 次比较,因此复杂度为 O(n2 ) ; 而穷举法需要 次加法, 次比较 , >O(n2n+1 ) 。
第二小节 动态规划问题
——货郎担问题
1. 动态规划 方法的思想
--- 动态规划 是一种将问题实例分解为更小的、相似的子问题,并存储子问题的解而避免计算重复的子问题,以解决最优化问题的算法策略。
2. 货郎担问题:
--- 某售货员要到若干个村庄售货,各村庄之间的路程是已知的,为了提高效率,售货员决定从所在商店出发,到每个村庄售一次货然后返回商店,问他应选择一条什么路线才能使所走的总路程最短?
实质 - -- 从某点出发,遍历其余点,再回到原点,求总路径消耗最少的路线.
[例]设共有4个要经过的点- --1,2,3,4---各个点之间的花费如下: 1--->2 : 10; 1--->3 : 15; 1--->4 : 20; 2--->1 : 5; 2--- >3 : 9; 2--- >4 : 10; 3--->1 : 6; 3--- >2 : 13; 3--- >4 : 12; 4--->1 : 8; 4--- >2 : 8; 4--- >3 : 9; (最短路径 :1--- >2--->4--->3--->1))
2 4 5
6 7
5
8
5 8
7 8 5
3. 问题的解决
1.) 问题的描述:
l T(V1; V) --- 表示从V1 出发, 经过顶点集合V 中的点各一次, 再回到点
V1 的最短路径.
2.) 动态规划函数:
T(vi; V) = min{dij + T(vj ; V-{vj})} (vj 属于 V)
l T(vi; V): 就是 从V 中任何一点vi 出发, 经过V 中的点各一次, 再回到
点 vi 的最短路径.
l Dij: 表示从点vi 出发, 到某点vj 的耗费( 有方向性).
l 注: 这是一个递归定义的函数, 关键是每次的函数T(vi; V) 它所处理的点
集逐渐减少.
3.) 实例:( 如上图) 求从v1 出发的货郎担问题.
解: T(v1; V)= T(v1; v1, v2, v3, v4)
= min{ d12 + T(v2; v3, v4),
d13 + T(v3; v2, v4),
d14 + T(v4; v2, v3) }
// 实例意义: 初始的货郎担问题是从点v1 出发, 涉及其余3 点v2,v3,v4; 那按照动态规划“分而治之” 的思想( 这里就是把问题规模缩小, 而问题的数量可多一些), 我们可先计算分别从v2, v3, v4 出发, 涉及(v2, v3, v4) 三点的三条货郎担路线的路耗, 再各自加上相应的dij, 这样, 最后就得到3 个总路耗, 再做一个min 运算, 就可求出初始问题的解.
T(v2; v3, v4)= min { d23 + T(v3; v4), d24 + T(v4;v3)}
T(v3; v4)= d34 + T(v4, @)
T(v4; v3)= d43 + T(v3, @)
T(v4, @)= d41
T(v3, @)= d31
T(v3; v4)= d34+ d41=6+9=15
T(v4; v3)= d43+ d31=8+8=16
T(v2; v3, v4)= min { d23 + d34+ d41, d24 + d43+ d31}
= min { 7+6+9, 6+8+8}=22
同理:
T(v3; v2, v4) = min { d32 + d24+ d41, d34 + d42+ d21 }
= min { 5+6+9, 6+5+4}=15
T(v4; v2, v3)= min { d42 + d23+ d31, d43 + d32+ d21}
= min { 5+7+8, 8+5+4}=17
则最后: T(v1; v1, v2, v3, v4)
= min{ d12 + T(v2; v3, v4),
d13 + T(v3; v2, v4),
d14 + T(v4; v2, v3) }
= min{ 2+22,5+15,8+17 }=20
所选的路线是:1->3->4->2->1
第三小节 动态规划问题
—— 投资问题
一 问题描述: 投资问题就是考虑如何把有限资源分配给若干个工程的问题。
二 给定条件: 1. 资源总数(设为 a )
2. 工程个数(设为 n )
3. 每项工程投资的利润(不同数目的投资所获得的利润不同),用向量 Gi (1 ≦ i ≦ n) 表示。
n
三 问题求解: 求出一个 a 的分划 x1 , x2 ,….., xn ,0 ≦ xi ≦ a, 且 ∑ xi ≦ a, 使得以下式表示的利润为最大:
i=1
n
G(a)= ∑ Gi (xj ) 0 ≦ xj ≦ a
i=1
其中 Gi (xj ) 是把资源 xj 分配给第 I 项工程能获得的最大利润。
四 问题分析:
i )若 Gi 是 x 的线性函数,则为线性规划问题。
ii )若 Gi 不是线性函数,则要用动态规划求最佳分配。
用总量为 a 的资金在 n 个项目上进行投资以取得最大的利润,可以转化为下述的问题:
将总量资金 a 分为两部分 z(0 ≦ z ≦ a) 及 a-z ,分别用在第 n 个项目及剩下的 n-1 个项目上进行投资,获得的最大利润 G(a)=max( 第 n 个项目上资金量为 z 的利润与用 a-z 的资金在 n-1 个项目上投资的最大利润之和 ) 。这样问题就转化为 ” 求用 a-z 的资金在 n-1 个项目上投资的最大利润 ” ,与我们的原问题 ” 求总量为 a 的资金在 n 个项目上进行投资以取得最大的利润 ” 性质完全一致,仅仅是问题的规模比原问题少了一个项目,如此将问题的规模细化下去,一直到项目数为 1 为止,则问题迎刃而解。我们在对原问题进行 ” 分而治之 ” 的过程当中,最终实现了最优化的求解。
五 问题解决方案:
设 fi (x) :前 i 个项目共投资资金 x 所产生的最大利润; di (x) :产生 fi (x) 在项目 i 上的资金数。
由上分析可给出投资问题的动态规划函数方程:
f1 (x)= G1 (x);
d1 (x)=x x=0,1……a
fi (x)=max[Gi (z)+ fi-1 (x-z)] z=0,1……x; x=0,1……a
di (x)= 产生 fi (x) 的 z 值 i=2,3…..n;
六 问题举例:
设有 8 (万元)的投资可分给 3 个项目,每个项目的利润函数如下表(一)所示:
表(一)利润函数表
x |
0 1 2 3 4 5 6 7 8 |
G1 (x) G2 (x) G3 (x) |
0 5 15 40 80 90 95 98 100 0 5 15 40 60 70 73 74 75 0 4 26 40 45 50 51 52 53 |
解题步骤:
第 1 步:设项目 1 是可用于投资的唯一项目,把 x 万元投资到项目 1 ,利润为
f1 (x)= G1 (x)
这就得到表(二)的最后一行的值,投资到项目 1 的最优数量为
d1 (x)=x x=0,1……8 ;
第二步:设资金 8 万元可投资到项目 1 和项目 2 。由第 1 步已知任意数量的资源投资到项目 1 所产生的最优,所以下到各种和式中的最大值就是目前情况下的最大利润:
G2 (0)+ f1 (8)=0+100=100 G2 (1)+ f1 (7)=5+98=103
G2 (2)+ f1 (6)=15+95=110 G2 (3)+ f1 (5)=40+90=130
G2 (4)+ f1 (4)=80+60=140 G2 (5)+ f1 (3)=70+40=110
G2 (6)+ f1 (2)=73+15=88 G2 (7)+ f1 (1)=74+5=79
G2 (8)+ f1 (0)=75+0=75
可见将 8 万元投资于项目 1 和 2 ,所能获得的最大利润 f2 (8) 及投资到项目 2 的最优数量分别为:
f2 (8)=max[G2 (z)+ f1 (8-z)]=140 z=0,1……8
d2 (8)=4 ;
第三步:假设以任意 x( ≠ 8) 万元投资到项目 1 和 2 ,对每个 x 值,计算从项目 1 和 2 所产生的最优利润,即:
f2 (x)=max[G2 (z)+ f1 (x-z)] z=0,1……x;
投资到项目 2 的数量为
d2 (x)= 产生 f2 (x) 的 z 值。
得到所表(二)的结果。
第四步:将 8 万元投资于 3 个项目,这就是原问题。则 f3 (8) 应取下述各量的最大值:
G3 (0)+ f2 (8)=0+140=140 G3 (1)+ f2 (7)=4+120=124
G3 (2)+ f2 (6)=26+96=126 G3 (3)+ f2 (5)=40+90=130
G3 (4)+ f2 (4)=45+80=125 G3 (5)+ f2 (3)=50+40=90
G3 (6)+ f2 (2)=51+15=66 G3 (7)+ f2 (1)=52+5=57
G3 (8)+ f2 (0)=53+0=53
因此将 8 万元以最优方式投资到 3 个项目时所获得的最大利润及投资到项目 3 的分别为:
f3 (8) =G3 (0)+ f2 (8)=140
d3 (8)=0 ;
表(二)向项目 1 , 2 投资所到的利润表
x |
0 1 2 3 4 5 6 7 8 |
f1 (x) d1 (x) f2 (x) d2 (x) |
0 5 15 40 80 90 95 98 100 0 1 2 3 4 5 6 7 8 0 5 15 40 80 90 95 120 140 0 1 2 3 0 0 0 3 4 |
因为 d3 (8)=0 ;故剩下 8 万元要最优的投资到项目 1 和 2 中。由表(二)易知,当项目 1 和 2 可用时, d2 (8)=4 表示 投资到项目 2 的最优数量,因此项目 1 应投资剩下的 4 万元。
第四小节 动态规划问题
——矩阵连乘积问题
一、求矩阵的连乘积
1 、一个实际的例子(体现了乘积顺序对矩阵连乘的重要性)
a) 例子 在讲这个问题之前先举个例子——
M = A *B *C ,其中 A=( aij )10*100 B=( bij )100*5 C=( cij )5*50
根据矩阵乘法的结合律,则有 M =( A *B ) *C 和 M = A * ( B*C ) 两个方案
但是可以发现他们所做的乘法的次数是不相同的
以 M =( A *B ) *C 为例
令 AB=M ‘ =(m ’ ij )10*5 ,因此 m ’ ij = (其中 ,I=1,2 …… 10 ; j = 1 , 2 …… 5 )故计算 AB 共进行了 10*5*100=5000 次乘法
M= M ‘ C = (其中 ,I=1,2 …… 10 ; j = 1 , 2 …… 50 )故计算 M ‘ C 共进行了 10*5*50=2500 次乘法
总共需要 5000 + 2500 = 7500 次乘法
同理, M = A * ( B*C )方案需要 100*5*50+10*100*50=25000+50000=75000 次乘法,两者相差近十倍!!!
B )结论
不难得出,矩阵相乘的结合方式对计算结果所需要的乘法操作总数有很大的影响。但是 M 相乘的个数增多至 n 个,求出所有的可能结合方式的乘法操作次数,再从中找出操作次数最小的结合方式,其工作量是惊人的 @!
对于 n 个矩阵的连乘积,设有 P ( n )个不同的计算次序。由于我们可以先在第 k 和 k + 1 个矩阵之间将原矩阵序列分为两个矩阵子序列, k = 1 , 2 ,…… n - 1 。然后分别对这两个矩阵子序列完全加括号。最后对所得结果加括号,得到原矩阵序列得一种完全加括号方式。由此,可以得到关于 P ( n )得递归式如下:
P ( n ) =1 , n=1 时
P ( n )= , n>1 时
解此递归方程可得, P ( n )= C ( n - 1 )其中, C ( n )= =
P ( n ) =P(1)P(n-1)+P(2)P(n-2)+ ……+ P ( n - 1 ) P ( 1 )
P ( 2 )= 1
P ( n )=
这样的话这种枚举的方法实际上是不可能的。
这里用动态规划的方法可以提供一种 O ( n3 )的算法。如果可以找出乘法次数最少的的结合方式来计算的话,那么就减少了不少工作量。
2 、动态规划法求解的方案(还是以一个实际的例子来讲动态规划法的算法)
a ) 算法分析举例
最佳的乘积方案是( A1 A2 …… Ai )( AI + 1 AI + 2 …… An )则 A1 A2 …… Ai 和 AI + 1 AI + 2 …… An 必须达到最佳。令 mij 为计算乘积 AI AI + 1 …… Aj 的最少乘法数,显然有
mij = mii = 0 , I , j = 1 , 2 …… n
其中 mik 是求 AI AI + 1 …… Ak 乘积时最佳方案的乘积数目, m 会+ 1 ; j 是求 Ak + 1 Ak + 2 …… Aj
乘积时的最佳方案的乘积数, AI AI + 1 …… Ak 是 ri *rk+1 阶矩阵, Ak + 1 Ak + 2 …… Aj 是 rk+1 *rj+1 矩阵, ri rk+1 rj+1 是求( AI AI + 1 …… Ak )( Ak + 1 Ak + 2 …… Aj )所需的乘数法
利用上式将之变为多段判决即可
以计算以下 4 个矩阵为例
A1 = 30*35 , A2 = 35*15 , A3 = 15*5 , A4 = 5*10 n = 4 为例
m12 = 30*35*15=15750 = 30*35*15=15750
m23 = 35*15*5=2625
m34 = 15*5*10=750
m13 = min{ m12 +30*15*5, m23 +30*35*5}= min{ 15750+2250, 2625+5250}=7875
m24 = min{ m23 +30*5*10, m34 +35*15*10}= min{ 2625+1750, 750+5250}=4375
m14 = min{ m12 + m34 +30*15*10, m24 +30*35*10, m13 +30*5*10}= min{ 15750+4500,4375+10500, 7875+30*5*10}=9375
故最佳方案为:(( A1 ( A2 A3 )) A4 )
|
|
0 |
m12 |
m13 |
m14 |
|
0 |
m23 |
m24 |
|
|
0 |
m34 |
|
|
|
0 |
B ) 算法时间空间复杂性分析
计算顺序是沿着对角线进行的。
如果编程的话,程序如下(! c ++程序只供参考,不作为讲课内容)
void MatrixChain (int p, int n, int n*m, int **s)
{
for (int r=2; r<=n; r++)
for (int i=1; i<=n-r+1; i=i++)
{
int j=I+r-1;
m[i][j]=m[i+1][j]+P[i-1]*p[i]*p[j];
s[i][j]=I;
for (int k=i+1; k
{
int t=m[i][k]+m[k+1][j]+p[I-1]*p[k]*p[j];
if (t
}
}
}
计算量主要取决于程序中对 r , I , k 的三重循环。循环体内的计算量为 O ( 1 ),而三重循环的总次数为 O(n3 ), 由此该算法的计算时间上界为 O(n3 ) ,算法所占用的空间显然为 O(n2 ) ,显然比穷举搜索法有效的多。
二、动态规划的基本要素(综合讲过的几个例子 , 总结算法的基本要素)
从以上的最优计算次序的动态规划算法可以看出,这些算法的有效性依赖于问题本身所具有的两个重要性质:最优子结构性质和子问题重叠性质。从一般意义上讲,问题所具有的这两个重要的性质是该问题可用动态算法求解的基本要素。
1 最优子结构
设计动态规划算法的第一步通常是要刻画最优解的结构。当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。问题的最优解子结构性质提供了该问题可用动态规划求解的重要线索。
比如,在矩阵连乘积最优解计算次序问题中,我们注意到,若 A1 、 A2 …… An 的最优完全加括号方式在 Ak 和 AK + 1 之间将矩阵链断开,则由此确定的子链 A1 、 A2 …… Ak 和 AK + 1 、 AK + 2 …… An 得完全加括号方式也最优。即该问题具有最优解子结构性质。在分析该问题得最优解导出得其子问题得解不是最优的,然后再设法说明在这个假设下可构造出一个比原问题最优解更好的解,从而导致矛盾。
在动态规划算法中,问题的最优子结构性质使我们能够自底向上的方法递归的从子问题地最优解逐步构造出整个问题地最优解。同时,它也使我们能在相对小的子问题空间中考虑问题。例如,在矩阵连乘积最优解次序问题中,子问题空间是输入地矩阵链的所有不同子链组成的。所有不同子链的个数为 O ( n2 ),因而子空间规模为 O ( n2 )
2 重叠子问题
可用动态规划算法求解问题应具备地另一基本要素是子问题地重叠性质。在用递归算法自顶向下解此问题时。每次产生地子问题并不总是新问题,有些子问题被反复计算多次。多态规划算法正式利用了这种子问题地重叠性质,对每个问题只解一次,尔后将其解保存在一个表格中,当再次需解此问题时,只是简单地用常数时间查看一下结果。通常,不同地子问题个数随输入问题地大小呈多项式增长。因此,用动态规划算法通常只需多项式时间,从而得较高得解题效率。
例如,搜索法和动态规划求解矩阵连乘法(这里略去具体……)
由此可以看出,在解某个问题得直接递归算法所产生得递归数中,相同的子问题反复出现,并且不同子问题的个数又相对减少时,用动态规划算法是有效的
三、分治法和动态规划法的比较
动态规划算法与分治法类似,其根本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解,与分治法不同的是,适合于用动态规划法求解的问题,经分解得到的子问题往往不是互相独立的。 (!! 这里严求真已经提过了 )
若用分治法来求解这类问题,则分解得到的子问题数目太多,以至于最后解原问题需耗费指数时间。然而,不同子问题的数目常常只有多项式量级。
在用分治法求解时,有些子问题被重计算了很多次。如果我们保存已解决子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,从而得到多项式时间的算法。为了达到这个目的,我们可以用一个表来记录所有已解决的子问题的答案 。不管该子问题以后是否被用到,只要被计算过,就将其结果填入表中。这就是动态规划法的基本思路。具体的动态规划算法多种多样,但他们具有相同的填表格式。
!!!!!! !另外提一下 (-因为第五周的课上,石浩讲分治法求矩阵乘积时说无法看出分治法体现在哪里 , 后来在一本书上看到如下的解释-)
分治法中的矩阵乘法即 Strassen 矩阵乘法中。
其分之思想是,将幂为 2 的矩阵 A , B , C 中每一个矩阵都分成 4 个大小相等的子矩阵,每个矩阵都是 (n/2)*(n/2) 的方阵,由此可将方程 C = AB 重写为
=
分治法的基本思想是将一个矩阵为 n 的问题分解为 k 个规模较小的子问题,这些子问题的解合并得到原问题的解。
参考资料:
《算法分析与设计》 周培德 机械工业出版社 (教材)
《计算机算法设计与分析》王晓东 电子工业出版社
《算法与复杂性》 卢开澄 高等教育出版社
《计算机算法导引-设计与分析》 卢开澄 清华大学出版社
《计算机算法基础》 余祥宣 崔国华 邹海明 华中科技大学出版社