矩阵连乘问题《算法分析与设计》.docx
《矩阵连乘问题《算法分析与设计》.docx》由会员分享,可在线阅读,更多相关《矩阵连乘问题《算法分析与设计》.docx(3页珍藏版)》请在冰豆网上搜索。
![矩阵连乘问题《算法分析与设计》.docx](https://file1.bdocx.com/fileroot1/2022-10/26/9eb14aa4-c11c-4dd8-adfc-581136549c98/9eb14aa4-c11c-4dd8-adfc-581136549c981.gif)
矩阵连乘问题《算法分析与设计》
矩阵连乘问题《算法分析与设计》
设计性实验报告 课程名称:
实验题目:
组 长:
成员一:
成员二:
成员三:
系 别:
专业班级:
指导教师:
实验日期:
《算法分析与设计》矩阵连乘问题 数学与计算机科学系 一、实验目的和要求 实验目的 熟悉动态规划算法设计思想和设计步骤,掌握基本的程序设计方法,培养学生用计算机解决实际问题的能力。
实验要求 1、根据实验内容,认真编写源程序代码、上机调试程序,书写实验报告。
2、本实验项目考察学生对教材中核心知识的掌握程度和解决实际问题的能力。
3、实验项目可以采用集中与分散实验相结合的方式进行,学生利用平时实验课时间和课外时间进行实验,要求在学期末形成完整的项目程序设计报告。
二、实验内容提要 矩阵连乘问题 给定n个矩阵{A1,A2,…,An},其中,Ai与Ai+1是可乘的,i=1,2,…,n-1。
考查这n 个矩阵的连乘积A1,A2,…,An。
于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。
这种计算次序可以用加括号的方式来确定。
若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则可以依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。
完全加括号的矩阵连乘积可递归地定义为:
单个矩阵是完全加括号的; 矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的矩阵连乘积B和C的乘积并加括号,即A=。
三、实验步骤 下面考虑矩阵连乘积的最优计算次序问题的动态规划方法。
分析最优解的结构 设计求解具体问题的动态规划算法的第一步是刻画该问题的最优解结构特征。
对于矩阵乘积的最优计算次序问题也不例外。
首先,为方便起见,降矩阵乘积AiAi+1…Aj简记为A[i:
j]。
考查计算A[1:
n]的最优计算次序。
设这个计算次序在矩阵Ak和Ak+1之间将矩阵链断开,1 这个问题的一个关键特征是:
计算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]的次序也是最优的。
因此,矩阵连乘积计算次序问题的最优解包含着其子问题的最优解。
这种性质称为最优子结构性质。
问题的最优子结构性质是该问题可用动态规划算法求解的显著特征。
建立递归关系 -1- 对于矩阵连乘积的最优计算次序问题,设计算A[i:
j],1= 当i=j时,A[i:
j]=Ai为单一矩阵,无需计算,因此,m[i][i]=0,i=1,2,......,n。
当i 当i=j,m[i][j]=0; 当i 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]构造出相应的最优解。
计算最优值 根据计算m[i][j]的递归式,容易写一个递归算法计算m[i][n]。
.稍后将看到,简单的递归计算将耗费指数计算时间。
注意到在递归计算过程中,不同的子问题个数只有θ个。
事实上,对于1 用动态规划算法解此问题,可依据其递归式以自底向上的方式进行计算。
在计算过程中,保存已解决的子问题答案。
每个子问题只计算一次,而在后面计算时只需简单查一下,从而避免大量重复计算,最终得到多项式时间的算法。
下面给出的动态规划算法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]。
构造最优解 动态规划算法的第四步屎构造问题的最优解。
算法matrixChain只是计算出了最优值,并未给出最优解。
也就是说,通过算法matrixChain的计算,只知道最少数乘次数,还不知道具体应按什么次序做矩阵乘法才能达到最少的数乘次数。
事实上,算法matrixChain已记录了构造最优解所需要的全部信息。
S[i][j]中的数k表明计算矩阵链A[i:
j]的最佳方式应在矩阵Ak和Ak+1之间断开,即最优的加括号方式应为。
因此,从是[1][n]记录的信息可知计算A[1:
n]的最优加括号方式为.而A[1:
s[1][n]]的最优加括号方式为(A[s[1][s[1][n]]+1:
s[1][s[1][n]]]).同理可知确 -2- 定A[s[1][n]+1:
n]的最优加括号方式为是s[s1][n]+1][n]出断开,······,照此递推下去,最终可以确定A[1:
n]的最优完全加括号方式,即构造出问题的一个最优解。
下面的算法traceback按算法matrixChain计算出的断点矩阵s指示的加括号方式输出计算A[i:
j]的最优计算次序。
voidtraceback(inti,intj,ints[N+1])//用递归来实现输出得到最小数乘次数的表达式 { } 要输出A[1:
n]的最优计算次序只要调用上面的traceback即可。
对于上面所举得例子,通过调用算法traceback,可输出最优计算次序((A1(A2A3))((A4A5)A6))。
if(i==j){}else{ printf(\ traceback(i,s[i][j],s); traceback(s[i][j]+1,j,s); printf(\} printf(\ 四、实验实施的条件 计算机机房,微型计算机,VisualC++软件或C#。
五、程序代码 下面是算法的完整程序代码。
版本:
c语言版本;开发人员:
王东亮、唐浩、陶胜、赵强#include #defineN100//定义最大连乘的矩阵个数为100个 voidmatrixChain(intp,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*/ { intn=N;//定义m,s数组的都是n*n的,不用行列下标为0的元素,但包括在该数组中for(inti=1;i m[i][i]=0;/*将矩阵m的对角线位置上元素全部置0,此时应是r=1的情况,表示先计 算第一层对角线上个元素的值*/ for(intr=2;r -3- } } for(inti=1;i intj=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(intk=i+1;k intt=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];/*计算当断开位置k为从i到j的所有取值对应的(Ai*......*Ak)*(Ak+1*.......Aj)的数乘次数*/ voidtraceback(inti,intj,ints[N+1])//用递归来实现输出得到最小数乘次数的表达式{ } voidmain(){ 连乘*/ intm[N+1][N+1];//用m[i][j]二维数组来存储Ai*......Aj的最小数乘次数 ints[N+1][N+1];//用s[i][j]来存储使Ai......Aj获得最小数乘次数对应的断开位置k -4- intn;//用来存储矩阵的个数 intq[2*N];/*用q数组来存储最原始的输入,主要目的是为了检验这Nintp[N+1],flag=1;/*用p[i-1],p[i]数组来存储A的阶数,flag用来判断这N个矩阵是否满足if(i==j){}else{ printf(\ traceback(i,s[i][j],s); traceback(s[i][j]+1,j,s); printf(\} printf(\ 个矩阵是否满足连乘的条件*/
printf(\请输入矩阵的个数:
\scanf(\ for(inti=0;i for(i=1;i for(intj=1;j p[0]=q[0]; p[n]=q[2*n-1]; matrixChain(p,m,s);printf(\式子如下:
\\n\traceback(1,n,s);printf(\ printf(\最小数乘次数为%d\\n\ p[j]=q[2*j];{} flag=0;break;if(i%2==0){}else{} printf(\列************:
\printf(\printf(\请输入A%d的行:
\ scanf(\ if(i%2!
=0&&q[i]!
=q[i+1]) }else{}} printf(\这%d个矩阵不能连乘!
\\n\ -5- 实验结果:
一、输入正确的情况:
二、输入有误的情况:
-6- 六、编程体会 经过了几天的连续研究,终于小有收获,也渐渐理解了动态规划的基本思想,动态规划算法与分治法类似,其基本思想也是将待解问题分解成若干个子问题,先求解子问题,,然后从这些子问题的解得到原问题的解。
与分治法不同的是,适合于用动态规划法求解的问题,经分解得到的子问题往往不是相互独立的。
若用分治法解这类问题,则分解得到的子问题数目太多,以至于最后解决原问题需要耗费指数时间。
然而,不同子问题的数目常常只有多项式量级。
在分治法求解时,有些子问题被重复计算了多次。
如果能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,就可以避免大量重复计算,从而得到多项式时间算法。
为了达到这个目的,可以用一个表来记录所有已解决的子问题的答案,不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。
这就是动态规划的基本思想。
具体的动态规划算法是多种多样的,但它们具有相同的填表格式。
动态规划算法适用于解最优化问题。
通常可以按以下步骤设计动态规划算法:
找出最优解的性质,并刻画其结构特征;递归地定义最优值; 以自底向上的方式计算出最优值; 根据计算最优值时得到的信息,构造最优解。
虽然已经了解了动态规划算法的基本思想,而且也参考了书上的算法,但是实际的情况却并不是那么顺利,我按照书上编写程序之后,发现有很多逻辑错误,应该是编写环境不同,所以出现了一系列的问题,最后经过自己的多番研究发现了许多