《算法设计与分析》第3章 动态规划法
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
矩 阵 连 乘 A[1:n] 的 最 优 计 算 次 序 的 计 算 量 等 于 A[1:k]和A[k+1:n]两者的最优计算次序的计算量之和, 再加上A[1:k]和A[k+1:n]相乘的计算量。 如果两个子序列的计算次序不是最优的,则原矩阵 连乘的计算次序也不可能是最优的。
这就是说,矩阵连乘问题的最优解具有最优子结构 特性(原问题的最优解决定了子问题的最优解)。
第3章 动态规划
内容提要
1. 2.
百度文库
3.
4. 5. 6. 7.
8.
9.
矩阵连乘的计算量问题 一般方法和基本要素 K段图路径问题 最长公共子序列 凸多边形的三角剖分、多边形游戏 图像压缩问题 最优二叉搜索树 0/1背包 流水作业调度
1. 矩阵连乘
1.1 问题描述
给定n个矩阵{A1,A2,…,An}, 其中Ai (i=1,…,n的维 数为pi-1pi),并且相邻矩阵是可乘的。考察这n个矩 阵的连乘积A1A2…An的计算量。由于矩阵乘法满足结 合律,所以计算矩阵的连乘可有许多不同的计算次序。 矩阵连乘问题是确定计算矩阵连乘积的计算次序(加 括号),使得按照这一次序计算矩阵连乘积,需要的 “数乘”次数最少。 (((A1×A2) ×A3)×A4) (A1×((A2 ×A3)×A4))
【程序】矩阵连乘的 穷举法实现 int MatrixChain::LookupChain(int i, int j) { if(i==j) return 0; int u=LookupChain(i+1,j)+p[i-1]*p[i]*p[j]; //k=i s[i][j]=i; //记录最优分解位置 for ( int k=i+1;k<j; k++ ) { //遍历k int t=LookupChain(i,k)+LookupChain(k+1,j) +p[i]*p[k+1]*p[j+1]; if (t<u) { u=t; s[i][j]=k; //记录最优分解位置 } } int MatrixChain::LookupChain() return u; { } return LookupChain(1,n);
1 n 1 n 1 P ( n) P ( n) ( 4 n / n 3 / 2 ) P(k ) P(n k ) n 1 k 1
catalan数 http://baike.baidu.com/view/1163998.htm
穷举法实现
将矩阵连乘AiAi+1…Aj简记为A[i:j],其中ij。于是矩阵连乘 A1A1…An可记作A[1:n]。 将这一计算次序在矩阵Ak 和Ak+1 ,1k<n-1之间断开,则其 相应的完全加括号形式为((A1A2…Ak)(Ak+1Ak+2…An))。 可分别计算A[1:k]和A[k+1:n],然后将两个连乘积再相乘得到 A[1:n]。 矩阵连乘A[1:n]的计算量等于A[1:k]和A[k+1:n]两者的计算 量之和,再加上A[1:k]和A[k+1:n]相乘的计算量。通过遍历所 有可能的k,找出最优的计算次序。
for (int r=2; r<=n;r++) //和主对角线平行的其他次对角线 for (int i=1;i<=n;i++) { int j=i+r-1; m[i][j]=m[i+1][j]+p[i]*p[i+1]*p[j+1];//k=i s[i][j]=i; for (int k=i+1;k<j;k++) { int t=m[i][k] +m[k+1][j]+p[i]*p[k+1]*p[j+1]; if (t<m[i][j]) { m[i][j]=t; s[i][j]=k; } } 算法复杂度分析: } 算法matrixChain的主要计算量取决于算法中对r, return m[1][n]; i和k的3重循环。循环体内的计算量为O(1),而3
例如 4 个 矩 阵 连 乘 积 ABCD , 设 它 们 的 维 数 分 别 为 A:5010,B:1040, C:4030, D:305。
每种计算次序都可以用一个二叉树来表示
A B C D
已确定计算次序的矩阵连乘积称为已完全加括号 由于每种加括号方式都可以分解为两个子连乘积的加括 号问题,因此完全加括号的矩阵连乘积可递归地定义为: 矩阵连乘积A是完全加括号的,则A可表示为两个已完 全加括号的矩阵连乘积B和C的乘积,即A=(BC)。 其中单个矩阵视为已完全加括号的;
1.3 动态规划法求解
矩阵连乘AiAi+1…Aj 简记为A[i:j],其中ij。于是矩 阵连乘A1A1…An可记作A[1:n]。将这一计算次序在矩 阵Ak 和Ak+1 ,1k<n-1之间断开,则其相应的完全加 括号形式为((A1A2…Ak )(Ak+1Ak+2…An))。可 分别计算A[1:k]和A[k+1:n],然后将两个连乘积再相 乘得到A[1:n]。
}
重循环的总次数为O(n3)。因此算法的计算时间上 界为O(n3)。算法所占用的空间显然为O(n2)。
void MatrixChain::Traceback(int i,int j) { if(i==j) { cout<<'A'<<i;return;} if (i<s[i][j]) cout<<‘(’; //ai,ai+1,…,ak加括号 Traceback(i,s[i][j]); if (i<s[i][j]) cout<<')'; if(s[i][j]+1<j) cout<<'('; //ak+1,ak+2,…,aj加括号 Traceback(s[i][j]+1,j); if(s[i][j]+1<j) cout<<')'; } void MatrixChain::Traceback() { cout<<'('; Traceback(1,n); cout<<')'; cout<<endl; }
}
穷举法实现的改进
1≤i≤j≤n ,与A[i:j]子问题对应 因此,A[i:j]不同子问题的个数最多只有
由于有序对(i,j),
n n ( n 2 ) 2
由此可见,在递归计算时,许多子问题被重复计算多次
使用备忘录
每个已经计算的子问题建立备忘,即保存子问题的计算结果以备
例 6个矩阵连乘积A1A2A3A4A5A6,设它们的维数分别 为A1:3035,A2:3515 A3:155 A4:510,A5:1020, A6:2025。
0 1 0 1 2 0 3 3 3 0 3 3 3 4 0 3 3 3 5 5 0
2. 一般方法和基本要素
2.2 动态规划算法的基本要素 一、最优子结构
多段图G=(V,E)是一个带权有向图
3. 多段图问题
多段图G=(V,E)中的结点被划分成k 2个互不相交的 子集Vi,1 i k。其中V1和Vk分别只有一个结点,V1 包含源点(source)s,Vk包含汇点(sink)t。 对所有边<u,v> E, 多段图要求若u Vi,则v Vi +1,1 i k,每条边的权值为c(u,v)。 从s到t的路径长度是这条路径上边的权值之和,多段 图问题(multistage graph problem)是求从s到t的一 条长度最短的路径。
2.2 一般方法
设计一个动态规划算法,通常可以按以下几个 步骤进行:
(1)刻画最优解的子结构特性; (2)递归定义最优解值; (3)以自底向上方式计算最优解值; (4)根据计算得到的信息构造一个最优解。
其中,第(1)至(3)步是动态规划算法的基 本步骤。最优解值是最优解的目标函数的值。
3. 多段图问题
矩阵连乘计算次序问题的最优解包含着其子问题的最 优解。这种性质称为最优子结构性质。 在分析问题的最优子结构性质时,所用的方法具有普 遍性:首先假设由问题的最优解导出的子问题的解不 是最优的,然后再设法说明在这个假设下可构造出比 原问题最优解更好的解,从而导致矛盾。 利用问题的最优子结构性质,以自底向上的方式递归 地从子问题的最优解逐步构造出整个问题的最优解。 最优子结构是问题能用动态规划算法求解的前提。
注意:同一个问题可以有多种方式刻划它的最优子结构,有些 表示方法的求解速度更快(空间占用小,问题的维度低)
2.2 动态规划算法的基本要素
二、重叠子问题 递归算法求解问题时,产生的子问题不总是新问题,将被重 复计算多次。这种性质称为子问题的重叠性质。 动态规划算法,对每一个子问题只解一次,将其解保存在表 格中,当再次需要解此子问题时,只是简单地查看其解。
最优解的递推关系 定义m[i:j],表示矩阵连乘A[i:j]所需的最少计算 量 则有: i j 0 m[i ][ j ] i j minj{m[i ][ k ] m[k 1][ j ] pi 1 pk p j } i k
假设:N个矩阵的维数依序放在一维数组p中, 其中Ai的维数记为Pi-1×Pi
需要时引用,以避免相同子问题的重复求解。
【程序】矩阵连乘的备忘录方法 //m0 int MatrixChain::LookupChain(int i, int j) { if (m[i][j]>0) return m[i][j]; //子问题已解。 if(i==j) return 0; int u=LookupChain(i+1,j)+p[i]*p[i+1]*p[j+1]; s[i][j]=i; for (int k=i+1;k<j; k++) { int t=LookupChain(i,k)+LookupChain(k+1,j) +p[i]*p[k+1]*p[j+1]; if (t<u) { int MatrixChain::LookupChain() u=t; { s[i][j]=k; return LookupChain(1,n); 备忘录方法的控制结构与直接递归方法的控制结构相同,区别 } } 在于备忘录方法为每个解过的子问题建立了备忘录以备需要时 } 查看,避免了相同子问题的重复求解。 m[i][j]=u; return u; 矩阵连乘A[i:j]的最少计算量记为m[i,j] }
求解过程
为避免重复计算,自底向上求解 m[i][j] m[i][k], k=i,i+1,…j-1 m[k+1][j], k=i+1,…j-1
矩阵连乘问题的动态规划算法实现
【程序】矩阵连乘动态规划算法 class MatrixChain { public: MatrixChain(int mSize,int *p); int MChain(); // 基于动态规划法 int LookupChain(); //基于备忘录的分治法 void Traceback(); //输出最优解 ……
private: void Traceback(int i,int j); int LookupChain(int i, int j); int *p,**m,**s, n; }; int MatrixChain::MChain() { //求A[1:n]的最优解值 for (int i=1;i<=n;i++) m[i][i]=0; //主对角线
A=A1×A2×A3×…×An
A=(A1×A2×…×Ak) × (Ak+1×Ak+2×…×An)
B
C
1.2 穷举法
穷举法:列举出所有可能的计算次序,并计算出 每一种计算次序相应需要的数乘次数,从中找出 一种数乘次数最少的计算次序。
穷举法复杂度分析: 对于n个矩阵的连乘积,设其不同的计算次序有P(n)种。 由于每种加括号方式都可以分解为两个子连乘的加括号问题: (A1...Ak)(Ak+1…An)可以得到关于P(n)的递推式如下:
通常子问题个数随问题的大小呈多项式增长。因此用动态规 划算法只需要多项式时间,从而获得较高的解题效率。
动态规划法 .VS. 分治法
动态规划法的实质也是将较大问题分解为较小的同类 子问题,这一点上它与分治法类似。
分治法的子问题相互独立,相同的子问题被重复计算。 动态规划法利用问题的最优子结构特征,设计自底向 上的计算过程,通过从子问题的最优解逐步构造出整 个问题的最优解。避免重复计算。