1、算法设计与分析实验报告学 院 信息科学与技术学院 专业班级 软件工程 3班 学 号 20122668 姓 名 王建君 指导教师 尹治本 2014 年 10 月 实验四 矩阵相乘次序1、问题提出用动态规划算法解矩阵连乘问题。给定 n 个矩阵A 1,A2,An,其中 Ai 与 Ai+1 是可乘的,i=1,2,n-1。要算出这 n 个矩阵的连乘积 A1A2An。由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则可以依此次序反复调用 2 个矩阵相乘的标准算法计算出矩阵连乘积。完全
2、加括号的矩阵连乘积可递归地定义为: (1)单个矩阵是完全加括号的; (2)矩阵连乘积 A 是完全加括号的,则 A 可表示为 2 个完全加括号的矩阵连乘积 B 和 C 的乘积并加括号,即 A=(BC)。 例如,矩阵连乘积 A1A2A3A4 有 5 种不同的完全加括号的方式:(A 1(A 2(A 3A4),(A 1(A 2A3)A 4),(A 1A2)(A 3A4),(A 1(A 2A3)A 4),(A 1A2)A 3)A 4)。每一种完全加括号的方式对应于一个矩阵连乘积的计算次序,这决定着作乘积所需要的计算量。若 A 是一个 pq 矩阵,B 是一个 qr 矩阵,则计算其乘积 C=AB 的标准算法
3、中,需要进行 pqr 次数乘。 (3)为了说明在计算矩阵连乘积时,加括号方式对整个计算量的影响,先考察 3 个矩阵A 1,A2,A3连乘的情况。设这三个矩阵的维数分别为10100,1005,550。加括号的方式只有两种:(A 1A2)A 3),(A 1(A 2A3),第一种方式需要的数乘次数为 101005105507500,第二种方式需要的数乘次数为 100550101005075000。第二种加括号方式的计算量时第一种方式计算量的 10 倍。由此可见,在计算矩阵连乘积时,加括号方式,即计算次序对计算量有很大的影响。于是,自然提出矩阵连乘积的最优计算次序问题,即对于给定的相继 n 个矩阵A
4、1,A2,An(其中矩阵 Ai 的维数为pi-1pi,i1,2,n),如何确定计算矩阵连乘积 A1A2An 的计算次序(完全加括号方式),使得依此次序计算矩阵连乘积需要的数乘次数最少。2、求解思路本实验采用动态规划算法解矩阵连乘积的最优计算次序问题。本实验的算法思路是: 1)计算最优值算法MatrixChain():建立两张表(即程序中的*m和*s,利用二维指针存放),一张表存储矩阵相乘的最小运算量,主对角线上的值为0,依次求2个矩阵、3个矩阵、直到n个矩阵相乘的最小运算量,其中每次矩阵相乘的最小运算量都在上一次矩阵相乘的最小运算量的基础上求得,最后一次求得的值即为n个矩阵相乘的最小运算量;另
5、一张表存储最优断开位置。 2)输出矩阵结合方式算法 Traceback():矩阵结合即是给矩阵加括号,打印出矩阵结合方式,由递归过程 Traceback()完成。分三种情况: (1)只有一个矩阵,则只需打印出 A1; (2)有两个矩阵,则需打印出(A1A2 ); (3)对于矩阵数目大于 2,则应该调用递归过程 Traceback()两次,构造出最优加括号方式。 三、算法复杂度该算法时间复杂度最高为 。)( n3O4、实验源代码#include using namespace std; const int MAX = 100; /p 用来记录矩阵的行列,main 函数中有说明 /mij用来记录第
6、 i 个矩阵至第 j个矩阵的最优解 /s用来记录从哪里断开的才可得到该最优解 int pMAX+1,mMAXMAX,sMAXMAX; int n;/矩阵个数 int matrixChain() for(int i=0;in; coutpi; /测试数据可以设为 8 个矩阵分别为 /A110*15,A215*20,A320*5,A45*25,A525*20,A620*5,A75*23,A823,8 /则 p0-8=10,15,20,5,25,20,5,23,8 cout#include #define INFINITY 32767 /无穷大#define MAX 100/*bij=-1 子问题未
7、计算,递归计算 bij!=-1 子问题已计算,直接取计算结果另外,也可从 bij算出各种面额的钞票数*/int DynamicMemory(int t, int i ,int j,int bMAX) if(i=1)if(j%t1=0)bij=j/t1; elsebij=INFINITY;return bij;elseint x;if(bi-1j=-1) x=DynamicMemory(t,i-1,j,b); elsex=bi-1j;if(jy+1)?(y+1):x;return bij; void main() system(“title 软件 3 班 王建君 20122668 动态规划实现找零问题“);int t10,n,M;/n-钞票面额的个数 M-要找的钱数t0=0;printf(“请输入钞票面额的种数:n“);scanf(“%d“,printf(“请依次输入%d 种钞票的面额:n“,n);for(int i=1;i0) if(r=1;k-)if(pk!=0)printf(“面额为%d 的钞票数:%dn“,tk,pk); 5、结果分析