矩阵连乘问题算法分析与设计
矩阵连乘问题的算法

矩阵连乘问题的算法
一、矩阵连乘问题
矩阵连乘问题是指在矩阵计算中,给定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;}可结合我的另⼀篇关于贪⼼算法的博客进⾏⽐较,了解这两者的区别;。
矩阵连乘最优结合问题

矩阵连乘最优结合问题摘要:一、问题背景及意义二、矩阵连乘最优结合问题的定义和描述三、矩阵连乘最优结合问题的求解方法1.暴力枚举法2.贪心算法3.动态规划四、算法分析和比较五、矩阵连乘最优结合问题在实际应用中的案例六、总结与展望正文:一、问题背景及意义在计算机科学和运筹学领域,矩阵连乘最优结合问题(Matrix Multiplication Optimal Matching Problem,简称MMOP)引起了广泛关注。
该问题源于矩阵快速幂运算,旨在寻找一种高效的矩阵乘法结合方式,以降低时间复杂度。
矩阵连乘最优结合问题在图像处理、信号处理、矩阵快速幂等领域具有重要的实际意义。
二、矩阵连乘最优结合问题的定义和描述给定两个矩阵A和B,矩阵连乘最优结合问题就是在一个有向图G(A,B)中,寻找一条从顶点A到顶点B的路径,使得路径上的矩阵乘法次数最少。
路径上的矩阵乘法次数等于路径长度乘以矩阵A和B的规模。
求解该问题,就是寻找一个最优的路径,使得乘法次数最小。
三、矩阵连乘最优结合问题的求解方法1.暴力枚举法:对于每条从顶点A到顶点B的路径,计算路径长度乘以矩阵A和B的规模,然后排序。
选择最小乘法次数的路径作为最优路径。
该方法时间复杂度为O(nm^2),其中n和m分别为矩阵A和B的行数和列数。
2.贪心算法:在每一步中,选择当前最优的顶点作为下一个顶点,直到到达目标顶点B。
贪心算法能够在一定程度上找到最优解,但不一定能得到全局最优解。
3.动态规划:将矩阵连乘最优结合问题转化为一个最短路径问题。
定义一个矩阵D,其中D[i][j]表示从顶点i到顶点j的最小乘法次数。
从顶点A开始,依次计算每个顶点的前驱顶点,直到到达顶点B。
最后得到的路径即为最优路径。
动态规划方法的时间复杂度为O(nm^2)。
四、算法分析和比较暴力枚举法虽然简单易懂,但时间复杂度较高,不适合大规模数据的计算。
贪心算法在某些情况下可以找到最优解,但不是全局最优解。
矩阵连乘最优结合问题

矩阵连乘最优结合问题摘要:1.矩阵连乘最优结合问题介绍2.问题的背景和意义3.矩阵连乘的定义及性质4.最优结合问题的数学模型5.解决最优结合问题的方法6.实例分析7.总结与展望正文:矩阵连乘最优结合问题是指在多个矩阵连乘的过程中,如何使矩阵连乘的结果最优。
这个问题在数学、物理、计算机科学等领域有着广泛的应用。
例如,在图像处理、信号处理、机器学习等方面,矩阵连乘是最基本、最常用的操作之一。
因此,研究矩阵连乘的最优结合问题,对于提高这些领域的计算效率和准确性具有重要意义。
矩阵连乘的定义如下:给定两个矩阵A 和B,它们的乘积矩阵C 是由A 的每一行与B 的每一列对应元素相乘后求和得到的矩阵。
即C = A * B,其中A * B 的第i 行第j 列元素cij = ∑A 的第i 行第k 列元素akik * B 的第k 列第j 列元素bkj。
矩阵连乘具有结合律、交换律和分配律等性质。
最优结合问题可以数学模型表示为:给定m 个矩阵A1, A2, ..., Am,如何选择一个合适的结合方式,使得矩阵连乘的结果矩阵C 具有最小的误差或最大的准确度。
这个问题可以用图论、整数规划等方法来解决。
以图像处理为例,假设我们需要对一幅图像进行多次滤波处理,每次滤波都需要对图像的像素值进行矩阵连乘。
如果我们可以找到一种最优的结合方式,使得滤波结果的矩阵具有最小的误差,那么就可以提高图像处理的效果和速度。
总之,矩阵连乘最优结合问题是一个具有重要理论和实际意义的问题。
通过研究这个问题的解决方法,我们可以更好地理解和利用矩阵连乘的性质,从而在各个领域提高计算效率和准确性。
矩阵连乘算法

福州大学数学与计算机科学学院《计算机算法设计与分析》上机实验报告(2)i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj。
由于在计算是并不知道断开点k 的位置,所以k还未定。
不过k的位置只有j-i个可能。
因此,k是这j-i个位置使计算量达到最小的那个位置。
综上,有递推关系如下:若将对应m[i][j]的断开位置k记为s[i][j],在计算出最优值m[i][j]后,可递归地由s[i][j]构造出相应的最优解。
s[i][j]中的数表明,计算矩阵链A[i:j]的最佳方式应在矩阵Ak和Ak+1之间断开,即最优的加括号方式应为(A[i:k])(A[k+1:j)。
从s[1][n]记录的信息可知计算A[1:n]的最优加括号方式为(A[1:s[1][n]])(A[s[1][n]+1:n]),进一步递推,A[1:s[1][n]]的最优加括号方式为(A[1:s[1][s[1][n]]])(A[s[1][s[1][n]]+1:s[1][s[1][n]]])。
同理可以确定A[s[1][n]+1:n]的最优加括号方式在s[s[1][n]+1][n]处断开...照此递推下去,最终可以确定A[1:n]的最优完全加括号方式,及构造出问题的一个最优解。
3、动态规划迭代算法设计:用动态规划迭代方式解决此问题,可依据其递归式自底向上的方式进行计算。
在计算过程中,保存已解决的子问题的答案。
每个子问题只计算一次,而在后面需要时只需简单检查一下,从而避免了大量的重复计算,最终得到多项式时间的算法。
4、算法代码:1. //3d1-2 矩阵连乘动态规划迭代实现2. //A1 30*35 A2 35*15 A3 15*5 A4 5*10 A5 10*20 A6 20*253. //p[0-6]={30,35,15,5,10,20,25}4. #include "stdafx.h"5. #include <iostream>6. using namespace std;7.8. const int L = 7;9.10. int MatrixChain(int n,int **m,int **s,int *p); 11. void Traceback(int i,int j,int **s);//构造最优解 12.13. int main()14. {15. int p[L]={30,35,15,5,10,20,25};16.17. int **s = new int *[L];18. int **m = new int *[L];19. for(int i=0;i<L;i++)20. {21. s[i] = new int[L];22. m[i] = new int[L];23. }24.25. cout<<"矩阵的最少计算次数为:"<<MatrixChain(6,m,s,p)<<endl;26. cout<<"矩阵最优计算次序为:"<<endl;27. Traceback(1,6,s);28. return 0;29. }30.31. int MatrixChain(int n,int **m,int **s,int *p) 32. {33. for(int i=1; i<=n; i++)34. {35. m[i][i] = 0;36. }37. for(int r=2; r<=n; r++) //r为当前计算的链长(子问题规模)38. {39. for(int i=1; i<=n-r+1; i++)//n-r+1为最后一个r链的前边界40. {41. int j = i+r-1;//计算前边界为r,链长为r的链的后边界42.43. m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];//将链ij划分为A(i) * ( A[i+1:j] )44.45. s[i][j] = i;46.47. for(int k=i+1; k<j; k++)48. {49. //将链ij划分为( A[i:k] )* (A[k+1:j]) 50. int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];51. if(t<m[i][j])52. {53. m[i][j] = t;54. s[i][j] = k;55. }56. }57. }58. }59. return m[1][L-1];60. }61.62. void Traceback(int i,int j,int **s)63. {64. if(i==j) return;65. Traceback(i,s[i][j],s);66. Traceback(s[i][j]+1,j,s);67. cout<<"Multiply A"<<i<<","<<s[i][j];68. cout<<" and A"<<(s[i][j]+1)<<","<<j<<endl;69. }上述迭代算法的运行过程如下图所示:当R=2时,先迭代计算出: m[1:2]=m[1:1]+m[2:2}+p[0]*p[1]*p[2]; m[2:3]=m[2:2]+m[3:3]+p[1]*p[2]*p[3];。
算法设计与分析——矩阵连乘问题(动态规划)

算法设计与分析——矩阵连乘问题(动态规划)⼀、问题描述引出问题之前我们先来复习⼀下矩阵乘积的标准算法。
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(")");}三、总结。
算法分析与设计课程中矩阵连乘问题的教学探讨

算法分析与设计课程中矩阵连乘问题的教学探讨作者:刘文强周波桑海涛顾泽元韩娜来源:《教育教学论坛》2016年第18期摘要:文章介绍了算法分析与设计课程中矩阵连乘问题的动态规划算法,利用该算法解决了两道经典竞赛题目,即能量项链问题和石子合并问题。
对于能量项链问题,其求解思想是将其转换为一个环形矩阵连乘问题,然后求解这个环形矩阵连乘积所需的最大乘法次数。
对于石子合并问题,分析出它与矩阵连乘问题的相似性,从而借鉴矩阵连乘问题的求解方法实现求解。
通过这两个问题的求解,有助于学生举一反三,启发学生思维,以学致用,提高问题求解能力。
关键词:矩阵连乘问题;能量项链问题;石子合并问题中图分类号:G642.0 文献标志码:A 文章编号:1674-9324(2016)18-0206-03在算法分析与设计课程中,矩阵连乘问题[1-2]是一个可用动态规划方法求解的经典最优化问题,利用该问题可以有效地求解许多实际问题。
该问题描述为:给定n个矩阵A1,A2,…,An,其中矩阵Ai(1≤i≤n)的维数为pi×pi+1,即矩阵A1的维数为p1×p2,矩阵A2的维数为p2×p3,依此类推,矩阵An的维数为pn×pn+1。
考虑这n个矩阵的连乘积A1A2…An,由于矩阵乘法满足结合律,所以求解这个矩阵连乘积时可以有许多不同的计算次序,每种计算次序都有一个计算量,这里所说的计算量是指按照某种计算次序来计算一个矩阵连乘积时所需的乘法次数。
那么矩阵连乘问题就是要确定一个矩阵连乘积的一种最优计算次序,使得按照这种最优计算次序来计算一个矩阵连乘积时,所需要的乘法次数最少。
一、矩阵连乘问题的动态规划算法用记号A[i:j]来表示矩阵连乘积AiAi+1…Aj-1Aj。
定义一个二维数组m来保存求解一个矩阵连乘积时所需的最少乘法次数,数组元素m[i][j]保存的是求解矩阵连乘积A[i:j]时所需的最少乘法次数。
根据最优子结构性质,容易建立m[i][j]所满足的递推关系式如下。
矩阵连乘算法

福州大学数学与计算机科学学院《计算机算法设计与分析》上机实验报告(2)i<=k<j,则:m[i][j]=m[i][k]+m[k+1][j]+pi-1pkpj。
由于在计算是并不知道断开点k的位置,所以k还未定。
不过k的位置只有j-i个可能。
因此,k是这j-i个位置使计算量达到最小的那个位置。
综上,有递推关系如下:若将对应m[i][j]的断开位置k记为s[i][j],在计算出最优值m[i][j]后,可递归地由s[i][j]构造出相应的最优解。
s[i][j]中的数表明,计算矩阵链A[i:j]的最佳方式应在矩阵Ak和Ak+1之间断开,即最优的加括号方式应为(A[i:k])(A[k+1:j)。
从s[1][n]记录的信息可知计算A[1:n]的最优加括号方式为(A[1:s[1][n]])(A[s[1][n]+1:n]),进一步递推,A[1:s[1][n]]的最优加括号方式为(A[1:s[1][s[1][n]]])(A[s[1][s[1][n]]+1:s[1][s[1][n]]] )。
同理可以确定A[s[1][n]+1:n]的最优加括号方式在s[s[1][n]+1][n]处断开...照此递推下去,最终可以确定A[1:n]的最优完全加括号方式,及构造出问题的一个最优解。
3、动态规划迭代算法设计:用动态规划迭代方式解决此问题,可依据其递归式自底向上的方式进行计算。
在计算过程中,保存已解决的子问题的答案。
每个子问题只计算一次,而在后面需要时只需简单检查一下,从而避免了大量的重复计算,最终得到多项式时间的算法。
4、算法代码:1.//3d1-2 矩阵连乘动态规划迭代实现2.//A1 30*35 A2 35*15 A3 15*5 A4 5*10 A5 10*20 A6 20*253.//p[0-6]={30,35,15,5,10,20,25}4.#include "stdafx.h"5.#include <iostream>ing namespace std;7.8.const int L = 7;9.10.int MatrixChain(int n,int **m,int **s,int *p);11.void Traceback(int i,int j,int **s);//构造最优解12.13.int main()14.{15.int p[L]={30,35,15,5,10,20,25};16.17.int **s = new int *[L];18.int **m = new int *[L];19.for(int i=0;i<L;i++)20. {21. s[i] = new int[L];22. m[i] = new int[L];23. }24.25. cout<<"矩阵的最少计算次数为:"<<MatrixChain(6,m,s,p)<<endl;26. cout<<"矩阵最优计算次序为:"<<endl;27. Traceback(1,6,s);28.return 0;29.}30.31.int MatrixChain(int n,int **m,int **s,int *p)32.{33.for(int i=1; i<=n; i++)34. {35. m[i][i] = 0;36. }37.for(int r=2; r<=n; r++) //r为当前计算的链长(子问题规模)38. {39.for(int i=1; i<=n-r+1; i++)//n-r+1为最后一个r链的前边界40. {41.int j = i+r-1;//计算前边界为r,链长为r的链的后边界42.43. m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];//将链ij划分为A(i) * ( A[i+1:j] )44.45. s[i][j] = i;46.47.for(int k=i+1; k<j; k++)48. {49.//将链ij划分为( A[i:k] )* (A[k+1:j])50.int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];51.if(t<m[i][j])52. {53. m[i][j] = t;54. s[i][j] = k;55. }56. }57. }58. }59.return m[1][L-1];60.}61.62.void Traceback(int i,int j,int **s)63.{64.if(i==j) return;65. Traceback(i,s[i][j],s);66. Traceback(s[i][j]+1,j,s);67. cout<<"Multiply A"<<i<<","<<s[i][j];68. cout<<" and A"<<(s[i][j]+1)<<","<<j<<endl;69.}上述迭代算法的运行过程如下图所示:当R=2时,先迭代计算出: m[1:2]=m[1:1]+m[2:2}+p[0]*p[1]*p[2];m[2:3]=m[2:2]+m[3:3]+p[1]*p[2]*p[3];。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
矩阵连乘问题《算法分析与设计》设计性实验报告课程名称:《算法分析与设计》矩阵连乘问题实验题目:长:组员一:成二:成员成员三:数学与计算机科学系别:系专业班级:指导教师:实验日期:一、实验目的和要求实验目的熟悉动态规划算法设计思想和设计步骤,掌握基本的程序设计方法,培养学生用计算机解决实际问题的能力。
实验要求1、根据实验内容,认真编写源程序代码、上机调试程序,书写实验报告。
2、本实验项目考察学生对教材中核心知识的掌握程度和解决实际问题的能力。
3、实验项目可以采用集中与分散实验相结合的方式进行,学生利用平时实验课时间和课外时间进行实验,要求在学期末形成完整的项目程序设计报告。
二、实验内容提要矩阵连乘问题给定n个矩阵{A,A,…,A},其中,Ai与Ai+1是可乘的,n21A,A,…,A。
由于矩阵乘法满足结n-1。
考查这n个矩阵的连乘积i=1,2,…,n12合律,故计算矩阵的连乘积可以有许多不同的计算次序。
这种计算次序可以用加括号的方式来确定。
若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则可以依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。
完全加括号的矩阵连乘积可递归地定义为:(1)单个矩阵是完全加括号的;(2)矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的矩阵连乘积B和C的乘积并加括号,即A=(BC)。
三、实验步骤下面考虑矩阵连乘积的最优计算次序问题的动态规划方法。
(1)分析最优解的结构(最优子结构性质)设计求解具体问题的动态规划算法的第一步是刻画该问题的最优解结构特征。
对于矩阵乘积的最优计算次序问题也不例外。
首先,为方便起见,降- 1 -矩阵乘积Ai Ai+1…Aj简记为A[i:j]。
考查计算A[1:n]的最优计算次序。
设这个计算次序在矩阵Ak和Ak+1之间将矩阵链断开,1<=k<n,则其相应的完全加括号方式为((A1…Ak)(Ak+1…An))即依此次序,先计算A[1:k]和 A[k+1:n],然后将计算结果相乘得到A[1:n]。
依此计算次序,总计算量为A[1:k]的计算量加上A[k+1:n]的计算量,再加上A[1:k]和A[k+1:n]相乘的计算量。
这个问题的一个关键特征是:计算A[1:n]的最优次序所包含的计算矩阵子链A[1:k]和A[k+1:n]的次序也是最优的。
事实上,若有一个计算A[1:k]的次序需要的计算量更少,则用此次序替换原来计算A[1:k]的次序,得到的计算A[1:n]的计算量将比按最优次序计算所需计算量更少,这是一个矛盾。
同理可知,计算A[1:n]的最优次序所包含的计算矩阵子链A[k+1:n]的次序也是最优的。
因此,矩阵连乘积计算次序问题的最优解包含着其子问题的最优解。
这种性质称为最优子结构性质。
问题的最优子结构性质是该问题可用动态规划算法求解的显著特征。
(2)建立递归关系对于矩阵连乘积的最优计算次序问题,设计算A[i:j],1=<i=<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]。
事实上,若计算A[i:j]的最优次序在Ak和Ak+1之间断开,i=<k<j,则m[i][j]=m[i][k]+m[k+1][j]+p[i-1 ]*p[k]*p[j]。
由于在计算时并不知道断开点k的位置,所以k还未定。
不过k的位置只有j-i种可能,即k属于{i,i+1,......,j-1}。
因此,k是这j-i 个位置中使计算量达到最小的那个位置。
从而m[i][j]可以递归地定义为当i=j,m[i][j]=0; 当i<j,m[i][j]=min{m[i][k]+m[k+1][j]+p [i-1]*p[k]*p[j]},i=<k<j- 2 -m[i][j]给出了最优值,即计算A[i:j]所需的最少数乘次数。
同时还确定了计算A[i:j]的最优次序中的断开位置k,也就是说,对于这个k有m[i][j]=m[i][k]+m[k+1][j]+p[i-1 ]*p[k]*p[j]若将对应于m[i][j]的断开位置k记为s[i][j],在计算出最优值m[i][j]后,可递归地有s[i][j]构造出相应的最优解。
(3)计算最优值根据计算m[i][j]的递归式,容易写一个递归算法计算m[i][n]。
.稍后将看到,简单的递归计算将耗费指数计算时间。
注意到在递归计算过程中,不同的子问题个数只有θ(n^2)个。
事实上,对于1<=i<=j<=n不同的有序对(i,j)对应于不同的子问题。
因此,不同的子问题的个数最多只有n*(n-1)/2+n=θ(n^2)个。
由此可见,在递归计算时,许多子问题被重复计算多次。
这也是该问题可以动态规划算法求解的又一显著特征。
用动态规划算法解此问题,可依据其递归式以自底向上的方式进行计算。
在计算过程中,保存已解决的子问题答案。
每个子问题只计算一次,而在后面计算时只需简单查一下,从而避免大量重复计算,最终得到多项式时间的算法。
下面给出的动态规划算法matrixChain中,输入参数{p0,p1,p2....,pn}存储于数组p中。
算法除了输出最优值数组m外还输出记录最优断开位置的数组s。
算法matrixChain,首先计算出m[i][i]=0,i=1,2,....,n。
然后,根据递归式,按矩阵链长递增的方式依次计算m[i][i+1],i=1,2,.....,n-1,(矩阵链长度为2);m[i][i+2],i=1,2,.....n-2,(矩阵链长为3);......。
在计算m[i][j]时,只用到已计算出的m[i][k]和m[k+1][j]。
(4)构造最优解动态规划算法的第四步屎构造问题的最优解。
算法matrixChain只是计算出了最优值,并未给出最优解。
也就是说,通过算法matrixChain的计算,只知道最少数乘次数,还不知道具体应按什么次序做矩阵乘法才能达到最少的数乘次数。
- 3 -事实上,算法matrixChain已记录了构造最优解所需要的全部信息。
S[i][j]中的数k表明计算矩阵链A[i:j]的最佳方式应在矩阵Ak和Ak+1之间断开,即最优的加括号方式应为(A[i:k])(A[k+1:j])。
因此,从是[1][n]记录的信息可知计算A[1:n]的最优加括号方式为(A[1:s[1][n]])(A[s[1][n]+1:n]).而A[1:s[1][n]]的最优加括号方式为(A[1:s[1][s[1][n]]])(A[s[1][s[1][n]]+1:s[1][s[1][n] ]]).同理可知确定A[s[1][n]+1:n]的最优加括号方式为是s[s1][n]+1][n]出断开,······,照此递推下去,最终可以确定A[1:n]的最优完全加括号方式,即构造出问题的一个最优解。
下面的算法traceback按算法matrixChain计算出的断点矩阵s指示的加括号方式输出计算A[i:j]的最优计算次序。
void traceback (int i,int j,int s[][N+1])//用递归来实现输出得到最小数乘次数的表达式{if (i==j){printf (A%d,i);}else{printf (();traceback (i,s[i][j],s);traceback(s[i][j]+1,j,s); printf ());- 4 -}}要输出A[1:n]的最优计算次序只要调用上面的traceback(1,n,s)即可。
对于上面所举得例子,通过调用算法traceback(1,6,s),可输出最优计算次序((A1(A2A3))((A4A5)A6))。
四、实验实施的条件计算机机房,微型计算机,Visual C++ 6.0软件或C#。
五、程序代码下面是算法的完整程序代码。
版本:c语言版本;开发人员:王东亮、唐浩、陶胜、赵强#include <stdio.h>#define N 100//定义最大连乘的矩阵个数为100个void matrixChain (int p[],intm[N+1][N+1],ints[N+1][N+1])/*用m[i][j]二维数组来存储Ai*......Aj的最小数乘次数,用s[i][j]来存储使Ai......Aj获得最小数乘次数对应的断开位置k,需要注意的是此处的N+1非常关键,虽然只用到的行列下标只从1到N但是下标0对应的元素默认也属于该数组,所以数组的长度就应该为N+1*/- 5 -{int n=N;//定义m,s数组的都是n*n的,不用行列下标为0的元素,但包括在该数组中for (int i=1;i<=n;i++)m[i][i]=0; /*将矩阵m的对角线位置上元素全部置0,此时应是r=1的情况,表示先计算第一层对角线上个元素的值*/ for (int r=2;r<=n;r++)//r表示斜对角线的层数,从2取到n{for (int i=1;i<=n-r+1;i++)//i 表示计算第r层斜对角线上第i行元素的值{int j=i+r-1;//j表示当斜对角线层数为r,行下标为i时的列下标m[i][j]=m[i+1][j]+p[i-1]*p[i]*p [j];//计算当断开位置为i时对应的数乘次数s[i][j]=i;//断开位置为ifor (int k=i+1;k<j;k++){- 6 -intt=m[i][k]+m[k+1][j]+p[i-1]*p[k] *p[j];/*计算当断开位置k为从i到j(不包括i和j)的所有取值对应的(Ai*......*Ak)*(Ak+1*.......Aj)的数乘次数*/if (t<m[i][j]){m[i][j]=t;//将Ai*......Aj的最小数乘次数存入m[i][j]s[i][j]=k;//将对应的断开位置k 存入s[i][j]}}}}}void traceback (int i,int j,int s[][N+1])//用递归来实现输出得到最小数乘次数的表达式{if (i==j){printf (A%d,i);- 7 -}else{printf (();traceback (i,s[i][j],s); traceback(s[i][j]+1,j,s); printf ());}}void main (){int n;//用来存储矩阵的个数int q[2*N];/*用q数组来存储最原始的输入(各矩阵的行和列),主要目的是为了检验这N个矩阵是否满足连乘的条件*/ int p[N+1],flag=1;/*用p[i-1],p[i]数组来存储A的阶数,flag 用来判断这N个矩阵是否满足连乘*/int m[N+1][N+1];// 用m[i][j]二维数组来存储Ai*......Aj的最小数乘次数 int s[N+1][N+1];// 用s[i][j]来存储使Ai......Aj获得最小数乘次数对应的断开位置k- 8 -牰湩晴?请输入矩阵的个数(小于100):); scanf (%d,&n);for (int i=0;i<=2*n-1;i++)//各矩阵的阶数的输入先存入数组q中接受检验{if (i%2==0){printf(********************\n); printf (*请输入A%d的行:,(i/2)+1);}else{牰湩晴?列************:);}scanf (%d,&q[i]);}for (i=1;i<=2*n-2;i++)//矩阵连乘条件的检验{if (i%2!=0&&q[i]!=q[i+1]) {flag=0;break;- 9 -}}for (int j=1;j<=n-1;j++){p[j]=q[2*j];}if (flag!=0){p[0]=q[0];p[n]=q[2*n-1];matrixChain (p,m,s); p楲瑮?尨式子如下:\n); traceback(1,n,s);printf (\);牰湩晴?最小数乘次数为%d\n,m[1][n]);}else{牰湩晴?这%d个矩阵不能连乘!\n,n); }}实验结果:- 10 -一、输入正确的情况:二、输入有误的情况:- 11 -六、编程体会经过了几天的连续研究,终于小有收获,也渐渐理解了动态规划的基本思想,动态规划算法与分治法类似,其基本思想也是将待解问题分解成若干个子问题,先求解子问题,,然后从这些子问题的解得到原问题的解。