动态规划矩阵连乘算法

合集下载

动态规划矩阵连乘算法

动态规划矩阵连乘算法

问题解析:由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。

这种计算次序可以用加括号的方式来确定。

若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则可以依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。

完全加括号的矩阵连乘积可递归地定义为:(1)单个矩阵是完全加括号的;(2)矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的矩阵连乘积B和C的乘积并加括号,即A=(BC)例如,矩阵连乘积A1A2A3A4有5种不同的完全加括号的方式:(A1(A2(A3A4))),(A1((A2A3)A4)),((A1A2)(A3A4)),((A1(A2A3))A4),(((A1A2)A3)A4)。

每一种完全加括号的方式对应于一个矩阵连乘积的计算次序,这决定着作乘积所需要的计算量。

看下面一个例子,计算三个矩阵连乘{A1,A2,A3};维数分别为10*100 , 100*5 , 5*50 按此顺序计算需要的次数((A1*A2)*A3):10X100X5+10X5X50=7500次,按此顺序计算需要的次数(A1*(A2*A3)):10*5*50+10*100*50=75000次所以问题是:如何确定运算顺序,可以使计算量达到最小化。

算法思路:例:设要计算矩阵连乘乘积A1A2A3A4A5A6,其中各矩阵的维数分别是:A1:30*35; A2:35*15; A3:15*5; A4:5*10; A5:10*20; A6:20*25递推关系:设计算A[i:j],1≤i≤j≤n,所需要的最少数乘次数m[i,j],则原问题的最优值为m[1,n]。

当i=j时,A[i:j]=A i,因此,m[i][i]=0,i=1,2,…,n当i<j时,若A[i:j]的最优次序在A k和A k+1之间断开,i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+p i-1p k p j。

动态规划-(矩阵连乘)

动态规划-(矩阵连乘)
} return m[0][n-1]; }
12
4、构造最优解
void MatrixChain::Traceback(int i, int j) {
if(i==j) { cout<<'A'<<i; return;} if (i<s[i][j]) cout<<'('; Traceback(i, s[i][j]); if (i<s[i][j])cout<<')'; if(s[i][j]+1<j)cout<<'('; Traceback(s[i][j]+1, j); if(s[i][j]+1<j) cout<<')'; } void MatrixChain::Traceback() { cout<<'('; Traceback(0, n-1); cout<<')'; cout<<endl; }
②当i=j时,A[i:j]=Ai,因此,m[i][i]=0,i=1,2,…,n ③当i<j时,m [ i ] j ] [ m [ i ] k ] [ m [ k 1 ] j ] [ p i 1 p k p j
这里 A i 的维数为 pi1pi
∴可以递归地定义m[i][j]为:
m [i]j] [ m i k j{ m [i]n k [ ] m [k 0 1 ]j] [ p i 1 p kp j}i i j j
根据MatrixChain动态规划算法: ②计算m[i][j]数乘次数
m[2][5]=min m[2][2]+m[3][5]+p1p2p5=13000

矩阵连乘问题的算法

矩阵连乘问题的算法

矩阵连乘问题的算法
一、矩阵连乘问题
矩阵连乘问题是指在矩阵计算中,给定n个矩阵,求这n个矩阵的连乘积的最优解问题。

矩阵连乘问题既可以用于组合优化,也可以用于信息处理系统中查找最优路径的搜索算法。

它是最基本的组合优化问题。

二、矩阵连乘问题的算法
1. 动态规划法:动态规划法是求解矩阵连乘问题的常用算法。

它采用递归方法,将原问题分解为若干个子问题,然后求出各子问题的最优解,最后组合出原问题的最优解。

2. 贪心算法:贪心算法是一种经典的最优化算法,也可以用于求解矩阵连乘问题,即通过某种启发式规则,在每一步中都使最优决策,最终得到最优解。

3. 分支定界法:分支定界法是一种由搜索算法和界定法相结合而成的最优化算法,也可以用于求解矩阵连乘问题。

该算法按照树状的层次结构,向下搜索一个在每一步骤都使得当前最优的路径,然后上溯形成最优解。

4. 模拟退火算法:模拟退火算法是一种搜索算法,它可以用于求解矩阵连乘问题。

它采用一种模拟物理过程的原理,通过不断地改变解的状态,以求出相对最优解。

- 1 -。

矩阵连乘问题(动态规划算法)

矩阵连乘问题(动态规划算法)

矩阵连乘问题(动态规划算法)动态规划算法思想简介:将⼀个问题分解为多个⼦问题,这点和分治法类似,但是每个⼦问题不是独⽴的⽽是相互联系的,所以我们在求解每个⼦问题的时候可能需要重复计算到其他的⼦问题,所以我们将计算过的⼦问题的解放进⼀个表中,这样就能避免了重复计算带来的耗费,这就是动态规划的基本思想;⼀般地,动态规划思想⼀般⽤来解最优化问题,主要分为以下四个步骤:(1)找出最优解的性质,并刻画其结构特征;(2)递归地定义最优值;(3)以⾃底向上的⽅式计算出最优值;(4)根据计算得到的最优值时得到的信息,构造最优解;同时,问题的最优⼦结构性质也是该问题可⽤动态规划算法求解的显著特征,这⾥的最优⼦结构性质即指:问题的最优解也即代表着它的⼦问题有了最优解;问题描述:分析过程如下:(1)分析最优⼦结构的性质:(2)分析递归关系,以及利⽤⾃底向上的⽅式进⾏计算:(3)获取最优值和最优解:代码如下:#ifndef MATRIX_CHAIN_H#define MATRIX_CHAIN_Hvoid matrix_chain(int *p, int n, int **m, int **s);void traceback(int i, int j, int **s);#endif#include <iostream>#include "matrix_chain.h"using namespace std;//利⽤动态规划算法获取最优值void matrix_chain(int *p, int n, int **m, int **s) //p:各个矩阵的列数,n:矩阵个数,m:m[i:j]矩阵i到j的相乘次数,s:对应的分开位置{for (int i = 0; i < n; i++){m[i][i] = 0;}for (int r = 2; r <= n; r++){for (int i = 0; i < n - r + 1; 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 < j; k++){int t = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j];if (t < m[i][j]){m[i][j] = t;s[i][j] = k;}}}}}//利⽤s[i][j]获取最优解void traceback(int i, int j, int **s){if (i == j)return;traceback(i, s[i][j], s);traceback(s[i][j] + 1, j, s);cout << "Multiply A" << i << " , " << s[i][j];cout << "and A" << (s[i][j] + 1) << " , " << j << endl;}#include <iostream>#include "matrix_chain.h"using namespace std;int main(void){int matrix_num = 0; //矩阵个数cout << "请输⼊矩阵个数:" << endl;cin >> matrix_num;int **m = new int *[matrix_num];for (int i = 0; i < matrix_num; i++)m[i] = new int[matrix_num];int **s = new int *[matrix_num];for (int i = 0; i < matrix_num; i++)s[i] = new int[matrix_num];int *p = new int[matrix_num];cout << "请输⼊各矩阵的列数:" << endl;for (int i = 0; i < matrix_num; i++){cin >> p[i];}matrix_chain(p, matrix_num, m, s);traceback(0, matrix_num - 1, s);system("pause");return1;}可结合我的另⼀篇关于贪⼼算法的博客进⾏⽐较,了解这两者的区别;。

动态规划法解矩阵连乘问题

动态规划法解矩阵连乘问题

动态规划法解矩阵连乘问题实验内容给定n个矩阵{A1,A2,….An},其中Ai与Ai+1是可乘的,i=1,2,3。

,n-1。

我们要计算这n个矩阵的连乘积。

由于矩阵乘法满足结合性,故计算矩阵连乘积可以有许多不同的计算次序。

这种计算次序可以用加括号的方式确定。

若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则我们可依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。

解题思路将矩阵连乘积A(i)A(i+1)…A(j)简记为A[i:j],这里i <= j 。

考察计算A[i:j]的最优计算次序。

设这个计算次序在矩阵A(k)和A(k+1)之间将矩阵链断开,i <= k < j, 则其相应完全加括号方式为(A(i)A(i+1) …A(k)) * (A(k+1)A(k+2) …A(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 < j 时,m[i,j] = m[i,k] + m[k+1,j] + p(i-1)p(k)p(j) 这里A(i)的维数为p(i-1)*(i)( 注:p(i-1)为矩阵A(i)的行数,p(i)为矩阵A[i]的列数)实验实验代码#in elude <iostream>#in elude <vector>using n amespaee std ;class matrix_cha in{public:matrix_eha in(const vector <int> & c){ cols = c ;count = cols.size (); mc.resize (co unt);s.resize (co unt);for (i nt i = 0; i < count; ++i) { mc[i].resize (co unt); s[i].resize (co unt);}for (i = 0; i < count; ++i) { for (int j = 0; j < count; ++j) { mc[i][j] = 0 ;s[i][j] = 0 ;//记录每次子问题的结果void lookup_cha in () {__lookup_cha in (1, count - 1);min_count = mc[1][co unt - 1];cout << "min _multi_co unt = "<< min_count << endl ;//输出最优计算次序__trackback (1, count - 1);}//使用普通方法进行计算void calculate () {int n = count - 1; //矩阵的个数// r表示每次宽度// i,j表示从从矩阵i到矩阵j// k表示切割位置for (i nt r = 2; r <= n; ++ r) {for (int i = 1; i <= n - r + 1; ++ i) {int j = i + r - 1 ;//从矩阵i到矩阵j连乘,从i的位置切割,前半部分为0mc[i][j] = mc[i+1][j] + cols[i-1] * cols[i] * cols[j];s[i][j] = i ;for (int k = i + 1; k < j; ++ k) {int temp = mc[i][k] + mc[k + 1][j] +cols[i-1] * cols[k] * cols[j];if (temp < mc[i][j]) {mc[i][j] = temp ;s[i][j] = k ;}} // for k} // for i} // for rmin_count = mc[1][ n];cout << "min _multi_co unt = "<< min_count << endl ;//输出最优计算次序__trackback (1, n);private:int __lookup_cha in (int i, i nt j) {//该最优解已求出,直接返回if (mc[i][j] > 0) {return mc[i][j];}if (i == j) {return 0 ; //不需要计算,直接返回}//下面两行计算从i到j按照顺序计算的情况int u = __lookup_cha in (i, i) + __lookup_cha in (i + 1, j)+ cols[i-1] * cols[i] * cols[j];s[i][j] = i ;for (int k = i + 1; k < j; ++ k) {int temp = __lookup_cha in (i, k) + __lookup_cha in(k + 1, j)+ cols[i - 1] * cols[k] * cols[j];if (temp < u) {u = temp ;s[i][j] = k ;}}mc[i][j] = u ;return u ;}void __trackback (int i, i nt j) {if (i == j) {return ;}__trackback (i, s[i][j]);__trackback (s[i][j] + 1, j);cout <<i << "," << s[i][j] << " " << s[i][j] + 1 << "," << j << endl;}private:vector<int> cols ; // 列数int count ; // 矩阵个数+ 1vector<vector<int> > mc; //从第i个矩阵乘到第j个矩阵最小数乘次数vector<vector<int> > s; //最小数乘的切分位置int min_count ; //最小数乘次数};int mai n(){//初始化con st i nt MATRIX_COUNT = 6 ;vectorvi nt> c(MA TRIX_COUNT + 1);c[0] = 30 ;c[1] = 35 ;c[2] = 15 ;c[3] = 5 ;c[4] = 10 ;c[5] = 20 ;c[6] = 25 ;matrix_cha in me (c); // mc.calculate (); mc」o okup_cha in (); return 0 ;}实验结果实验验证从s 可知计算顺序为((A1(A2A3))((A4A5))A6))实验总结在这次实验中懂得了动态规划法运用方法和解题思路的重要性,在这个程序中如何 建立动态规划的过程建立递归过程 保存已解决的子问题答案。

动态规划之矩阵连乘 算法设计

动态规划之矩阵连乘 算法设计

动态规划之矩阵连乘卓淑琴(安徽中医学院医药信息工程;安徽合肥 230009)摘要:动态规划是求解最优化问题的一种方法,该文主要研究其求解问题的基本思想及其具体步骤,详细分析其用于矩阵连乘问题上的算法设计。

关键词:动态规划,矩阵连乘,最优解中图分类号:TP360.1 文献标识码:AThe dynamic programming of matrix continuous multiplyZHUO Shu -qin(Medical information engineering institute An Hui University of Traditional Chinese Medicine, Hefei230009 Anhui)Abstract:The dynamic programming optimization problem solving is a kind of method, this paper mainly studies the basic idea of solving problem and its specific steps, and a detailed analysis on the matrix continuous multiply on the question of the algorithm design.Key words: Dynamic programming; Matrix continuous multiply ;The optimal solution.0.引言动态规划(dynamic programming)是运筹学的一个分支,是求解决策过程(decision process)最优化的数学方法。

20世纪50年代初美国数学家R.E.Bellman等人在研究多阶段决策过程(multistep decision process)的优化问题时,提出了著名的最优化原理(principle of optimality),把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解,创立了解决这类过程优化问题的新方法——动态规划。

算法设计与分析——矩阵连乘问题(动态规划)

算法设计与分析——矩阵连乘问题(动态规划)⼀、问题描述引出问题之前我们先来复习⼀下矩阵乘积的标准算法。

int ra,ca;//矩阵A的⾏数和列数int rb,cb;//矩阵B的⾏数和列数void matrixMultiply(){for(int i=0;i<ra;i++){for(int j=0;j<cb;j++){int sun=0;for(int k=0;k<=ca;k++){sum+=a[i][k]*b[k][j];}c[i][j]=sum;}}}给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2…,n-1。

如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。

例如,给定三个连乘矩阵{A1,A2,A3}的维数分别是10*100,100*5和5*50,采⽤(A1A2)A3,乘法次数为10*100*5+10*5*50=7500次,⽽采⽤A1(A2A3),乘法次数为100*5*50+10*100*50=75000次乘法,显然,最好的次序是(A1A2)A3,乘法次数为7500次。

加括号的⽅式对计算量有很⼤的影响,于是⾃然地提出矩阵连乘的最优计算次序问题,即对于给定的相继n个矩阵,如何确定矩阵连乘的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。

⼆、问题分析矩阵连乘也是Catalan数的⼀个常⽤的例⼦,关于时间复杂度的推算需要参考离散数学关于Catalan的内容。

下⾯考虑使⽤动态规划法解矩阵连乘积的最优计算次序问题。

1、分析最优解的结构问题的最优⼦结构性质是该问题可以⽤动态规划求解的显著特征!!!2、建⽴递归关系3、计算最优值public static void matrixChain(int n) {for (int i = 1; i <= n; i++) {m[i][i] = 0;}for (int r = 2; r <= n; r++) {//i与j的差值for (int i = 1; i <= n - r + 1; 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 < j; k++) {int t = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j];if (t < m[i][j]) {m[i][j] = t;s[i][j] = k;}}}}}4、构造最优解public static void traceback(int i, int j) {if (i == j) {System.out.printf("A%d", i); // 输出是第⼏个数据return;}System.out.printf("(");traceback(i, s[i][j]);// 递归下⼀个数据System.out.printf(" x ");traceback(s[i][j] + 1, j);System.out.printf(")");}三、总结。

矩阵链乘法(动态规划)

矩阵链乘法(动态规划)
⼀题意描述:
给定由n个要相乘的矩阵构成的序列(链)<A1,A2,A3,····A n>。

由于矩阵满⾜结合律(加括号⽅式表⽰结合⽅式),不同的计算⽅式导致的求出最终计算结果的代价相异,有的花的时间很少,有的⽅式所花时间很多,那么下⾯的任务就是求出算出结果所需要的最少时间及⼀个最优解。

⼆思路分析:
设p(n)表⽰⼀串n个矩阵可能的加全部括号⽅案数。

当n=1时,只有⼀个矩阵,此时p(1)=1。

当n>=2时,⼀个加全部括号的矩阵乘积等于两个加全部括号的⼦矩阵乘积的乘积,⽽且这两个⼦乘积之间的分裂可能发⽣在第k个和第k+1个矩阵之间,其中k=1,2,····,n-1;因此可以求得递归式:
1.找局部最优解:把问题:转化成两个最优⼦问题:及
2.构造递归解:
⾸先定义m[i,j]为解决⼦问题A[i....j]的最⼩计算次数,那么解决整个问题A[1,n]所花的最⼩时间为m[1,n]。

那么递归⽅程可以写成如下形式:
为了跟踪如何构造⼀个最优解我们可以定义s[i,j]为这样的⼀个k值,在该处分裂乘积后可得⼀个最优解。

3.构造函数进⾏求解
输出最优路径的函数⾃⼰编写,经过调⽤数组s[i][j]即可。

动态规划之矩阵链相乘问题(算法导论)

动态规划之矩阵链相乘问题(算法导论)问题描述:给定n个矩阵序列,(A1,A2,A3,A4,...,An). 计算他们的乘积:A1A2A3...An.由于矩阵的乘法运算符合结合律,因⽽可以通过调整计算顺序,从⽽降低计算量。

样例分析:⽐如有三个矩阵分别为:A1: 10*100,A2: 100*5,A3: 5*50假如现在按照(A1A2)A3的顺序计算需要的计算量为:10*100*5+10*5*50=7500次运算。

若按照A1(A2A3)的顺序计算,需要的计算量为:100*5*50+10*100*50=75000次运算。

上⾯两种不同的运算顺序所有的计算量相差⼗倍。

因⽽,⼀种最优的计算顺序将能很⼤程度的减少矩阵连乘的运算量。

问题解析:此问题的⽬的是寻找⼀种最优的括号化⽅案。

下⾯⽤动态规划的思想来进⾏分析:1、动态规划的第⼀步:寻找最优⼦结构。

为⽅便起见,使⽤Ai..j表⽰AiAi+1...Aj的乘积结果矩阵。

对于k(i<=k<j), 计算Ai..j所需要的计算量为:Ai..k 和 Ak+1..j 以及⼆者相乘的代价和。

2、设m[i][j]为Ai..j的最优计算顺序所要花费的代价。

则其求解公式为:if i == j, m[i][j] = 0; //因为只有⼀个矩阵时计算代码为0,即不需要计算。

m[i][j]=min{m[i][k] + m[k+1][j] + Pi-1PkPj} i<=k<j3、为了能够输出求解顺序,需要保存区间中的⼀些分割点。

假如Ai..j中的最优分割点为k,则我们使⽤s[i][j]=k。

即在Ai..j 中,分别计算Ai..k 和 Ak+1..j 所⽤的计算开销最⼩。

4、采⽤⾃底向上的表格法。

依次求解矩阵长度为2,3,...,n的最优计算顺序。

算法思想:1、对m[i][i]全部初始化为0.2、在矩阵链A1..n中,依次计算长度len为2,3,...,n的m[i][j]⼤⼩。

n个矩阵连乘问题

矩阵连乘问题是一个经典的优化问题,其目标是在给定一组矩阵和它们之间的乘法顺序下,找出最少的括号方案数,使得乘法操作可以按照给定的顺序进行。

假设有n个矩阵A1, A2, ..., An,我们需要计算它们的连乘积。

每个矩阵Ai都有m×m的元素。

矩阵连乘问题可以转化为以下动态规划问题:
1. 定义dp[i][j]为计算矩阵Ai到Aj的连乘积所需的最少括号方案数。

2. 初始化dp[i][i]=0,表示单个矩阵不需要任何括号。

3. 对于i<j,计算dp[i][j]的递推关系:
dp[i][j] = dp[i][k] + dp[k+1][j] + p[i-1]*p[k]*p[j],其中k=i,...,j-1。

其中p是任意一个正整数,表示矩阵的维度m。

4. 最终答案为dp[1][n]。

以下是Python代码实现:
计算结果为:最少需要15个括号方案数。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
当i=j时,A[i:j]=Ai,因此,m[i][i]=0,i=1,2,…,n
当i<j时,若A[i:j]的最优次序在Ak和Ak+1之间断开,i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj。由于在计算是并不知道断开点k的位置,所以k还未定。不过k的位置只有j-i个可能。因此,k是这j-i个位置使计算量达到最小的那个位置。
cout<<"矩阵最优计算次序为:"<<endl;
Traceback(1,6,s);
return 0;
}
int MemoizedMatrixChain(int n,int **m,int **s,int *p)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
m[i][j]=0;
}
}
return LookupChain(1,n,m,s,p);
}
int LookupChain(int i,int j,int **m,int **s,int *p)
{
if(m[i][j]>0)
{
return m[i][j];
}
if(i==j)
{
return 0;
}
int u = LookupChain(i,i,m,s,p) + LookupChain(i+1,j,m,s,p)+p[i-1]*p[i]*p[j];
2、重叠递归
从以上递推关系和构造最优解思路出发,即可写出有子问题重叠性的递归代码实现:
//3d1-1重叠子问题的递归最优解
//A1 30*35 A2 35*15 A3 15*5 A4 5*10 A5 10*20 A6 20*25
//p[0-6]={30,35,15,5,10,20,25}
#include "stdafx.h"
return u;
}
void Traceback(int i,int j,int **s)
{
if(i==j) return;
Traceback(i,s[i][j],s);
Traceback(s[i][j]+1,j,s);
cout<<"Multiply A"<<i<<","<<s[i][j];
cout<<" and A"<<(s[i][j]+1)<<","<<j<<endl;
}
算法通过数组m记录子问题的最优值,m初始化为0,表明相应的子问题还没有被计算。在调用LookupChain时,若m[i][j]>0,则表示其中存储的是所要求子问题的计算结果,直接返回即可。否则与直接递归算法一样递归计算,并将计算结果存入m[i][j]中返回。备忘录算法耗时O(n^3),将直接递归算法的计算时间从2^n降至O(n^3)。
const int L = 7;
int LookupChain(int i,int j,int **m,int **s,int *p);
int MemoizedMatrixChain(int n,int **m,int **s,int *p);
void Traceback(int i,int j,int **s);//构造最优解
问题描述:给定n个矩阵:A1,A2,...,An,其中Ai与Ai+1是可乘的,i=1,2...,n-1。确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数。
问题解析:由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则可以依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。
#include <iostream>
using namespace std;
const int L = 7;
int RecurMatrixChain(int i,int j,int **s,int *p);//递归求最优解
void Traceback(int i,int j,int **s);//构造最优解
{
s[i] = new int[L];
m[i] = new int[L];
s[i][j] = i;
for(int k=i+1; k<j; k++)
{
int t = RecurMatrixChain(i,k,s,p) + RecurMatrixChain(k+1,j,s,p) + p[i-1]*p[k]*p[j];
if(t<u)
{
u=t;
s[i][j]=k;
}
}
return u;
1、穷举法
列举出所有可能的计算次序,并计算出每一种计算次序相应需要的数乘次数,从中找出一种数乘次数最少的计算次序。
对于n个矩阵的连乘积,设其不同的计算次序为P(n)。每种加括号方式都可以分解为两个子矩阵的加括号问题:(A1...Ak)(Ak+1…An)可以得到关于P(n)的递推式如下:
以上递推关系说明,P(n)是随n的增长呈指数增长的。因此,穷举法不是一个多项式时间复杂度算法。
s[i][j]=i;
for(int k=i+1; k<j; k++)
{
int t = LookupChain(i,k,m,s,p) + LookupChain(k+1,j,m,s,p) + p[i-1]*p[k]*p[j];
if(t<u)
{
u=t;
s[i][j] = k;
}
}
m[i][j] = u;
3、动态规划迭代实现
用动态规划迭代方式解决此问题,可依据其递归式自底向上的方式进行计算。在计算过程中,保存已解决的子问题的答案。每个子问题只计算一次,而在后面需要时只需简单检查一下,从而避免了大量的重复计算,最终得到多项式时间的算法。
//3d1-2 矩阵连乘 动态规划迭代实现
//A1 30*35 A2 35*15 A3 15*5 A4 5*10 A5 10*20 A6 20*25
cout<<"矩阵最优计算次序为:"<<endl;
Traceback(1,6,s);
return 0;
}
int RecurMatrixChain(int i,int j,int **s,int *p)
{
if(i==j) return 0;
int u = RecurMatrixChain(i,i,s,p)+RecurMatrixChain(i+1,j,s,p)+p[i-1]*p[i]*p[j];
int main()
{
int p[L]={30,35 = new int *[L];
for(int i=0;i<L;i++)
{
s[i] = new int[L];
}
cout<<"矩阵的最少计算次数为:"<<RecurMatrixChain(1,6,s,p)<<endl;
看下面一个例子,计算三个矩阵连乘{A1,A2,A3};维数分别为10*100 , 100*5 , 5*50按此顺序计算需要的次数((A1*A2)*A3):10X100X5+10X5X50=7500次,按此顺序计算需要的次数(A1*(A2*A3)):10*5*50+10*100*50=75000次
所以问题是:如何确定运算顺序,可以使计算量达到最小化。
完全加括号的矩阵连乘积可递归地定义为:
(1)单个矩阵是完全加括号的;
(2)矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的矩阵连乘积B和C的乘积并加括号,即A=(BC)
例如,矩阵连乘积A1A2A3A4有5种不同的完全加括号的方式:(A1(A2(A3A4))),(A1((A2A3)A4)),((A1A2)(A3A4)),((A1(A2A3))A4),(((A1A2)A3)A4)。每一种完全加括号的方式对应于一个矩阵连乘积的计算次序,这决定着作乘积所需要的计算量。
}
void Traceback(int i,int j,int **s)
{
if(i==j) return;
Traceback(i,s[i][j],s);
Traceback(s[i][j]+1,j,s);
cout<<"Multiply A"<<i<<","<<s[i][j];
cout<<" and A"<<(s[i][j]+1)<<","<<j<<endl;
算法思路:
例:设要计算矩阵连乘乘积A1A2A3A4A5A6,其中各矩阵的维数分别是:
A1:30*35; A2:35*15; A3:15*5; A4:5*10; A5:10*20; A6:20*25
递推关系:
设计算A[i:j],1≤i≤j≤n,所需要的最少数乘次数m[i,j],则原问题的最优值为m[1,n]。
7.3、备忘录递归算法
相关文档
最新文档