首页 > 代码库 > 算法实验--矩阵连乘

算法实验--矩阵连乘

一、实验目的:

熟悉掌握动态规划法设计技术

二、实验要求:

1、按教材所授内容要求,完成“矩阵连乘问题”算法。得到一个完整正确的程序。

2、问题规模:不少于20

3、输出最终结果。

三、实验设备:

PC机一台

VC6.0编译软件

四、问题描述:

给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2,…,n-1。要算出这n个矩阵的连乘积A1A2…An。由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则可以依此次序反复调用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)。每一种完全加括号的方式对应于一个矩阵连乘积的计算次序,这决定着作乘积所需要的计算量。

若A是一个p×q矩阵,B是一个q×r矩阵,则计算其乘积C=AB的标准算法中,需要进行pqr次数乘。 为了说明在计算矩阵连乘积时,加括号方式对整个计算量的影响,先考察3个矩阵{A1,A2,A3}连乘的情况。设这三个矩阵的维数分别为10×100,100×5,5×50。加括号的方式只有两种:((A1A2)A3),(A1(A2A3)),第一种方式需要的数乘次数为10×100×5+10×5×50=7500,第二种方式需要的数乘次数为100×5×50+10×100×50=75000。第二种加括号方式的计算量时第一种方式计算量的10倍。由此可见,在计算矩阵连乘积时,加括号方式,即计算次序对计算量有很大的影响。于是,自然提出矩阵连乘积的最优计算次序问题.

 

 

 

五、算法分析:

动态规划算法的基本思想是将待求解问题分成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,动态规划法经分解得到的子问题往往不是相互独立的,前一子问题的解为后一子问题的解提供有用的信息,可以用一个表来记录所有已解决的子问题的答案,不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。 

本实验的算法思路是: 

void matrixChain();通过三重for循环找出每个子问题的最优解法的断点k和求出最优解。

void showChain(int *show);//以矩阵(行*列)方式显示出来,进入时通过输入矩阵个数和每个矩阵的行列数(只考虑了前一个矩阵的列等于后一个矩阵的行数的情况),将看的不是很清新明白的一串数字显示成[Ai:52*36]的形式。

void traceback(int i,int j);//"Multiply A2,1 and A3,2"的方式显示结果

void trace_back(int i, int j, int s[][MAX]);//"(A1(A2A3))"的方式显示结果,本实验中只用了③④中④的方法显示。

 

六、代码:

#include<iostream>

using namespace std;

const int MAX = 100;

//p用来记录矩阵的行列,m[i][j]用来记录第i个矩阵至第j个矩阵的最优解(代价最//小),k=s[][]用来记录从哪里断开的才可得到该最优解

int p[MAX+1],m[MAX][MAX],s[MAX][MAX];

int n;//矩阵个数

void matrixChain();

void showChain(int *show);//以矩阵(行*列)方式显示出来

void traceback(int i,int j);//"Multiply A2,1 and A3,2"的方式显示结果

void trace_back(int i, int j, int s[][MAX]);//"(A1(A2A3))"的方式显示结果

main(){

int show[MAX];

cout<<"请输入连乘矩阵的个数:\n";

cin>>n;

cout<<"请输入各矩阵的行列数(i>=2,输入数表示Ai列数和Ai+1行数(n+1个数)\n";

for(int i=0;i<=n;i++)

{

cin>>p[i];

show[i]=p[i];

}

showChain(show);

cout<<"计算顺序如下\n";

matrixChain();

trace_back(1,n,s);

//traceback(1,n);

//最终解值为m[1][n];

cout<<"\n"<<"数乘次数Count:"<<m[1][n]<<endl;

}

 

void showChain(int *show)

{

cout<<"矩阵行列数为:\n";

for(int i=0;i<n;i++){

if(i%6==0&&i/6!=0)cout<<"\n";

cout<<"A"<<i+1<<":"<<show[i]<<"*"<<show[i+1]<<" ";

}

cout<<"\n";

}

void matrixChain(){

for(int i=1;i<=n;i++)m[i][i]=0;

for(int r=2;r<=n;r++)//对角线循环

for(int i=1;i<=n-r+1;i++){//行循环

int j = r+i-1;//列的控制

//m[i][j]的最小值,先初始化一下,令k=i

m[i][j]=m[i][i]+m[i+1][j]+p[i-1]*p[i]*p[j];

s[i][j]=i;

//ki+1j-1循环找m[i][j]的最小值

for(int k = i+1;k<j;k++){

int temp=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];

if(temp<m[i][j]){

m[i][j]=temp;

//s[][]用来记录在子序列i-j段中,在k位置处断开能得到最优解

s[i][j]=k;

}

}

}

}

 

//根据s[][]记录的各个子段的最优解,将其输出

//void traceback(int i,int j){

//if(i==j)return ;

//traceback(i,s[i][j]);

//traceback(s[i][j]+1,j);

//cout<<"Multiply A"<<i<<","<<s[i][j]<<"and A"<<s[i][j]+1<<","<<j<<endl;

// }

void trace_back(int i, int j, int s[][MAX])  

{  

    if(i==j) {printf("A%d",i);return;}  

    printf("(");  

    trace_back(i,s[i][j],s);  

    trace_back(s[i][j]+1, j, s);  

    printf(")");  

}  

 

七、调试及运行:

1. 6个矩阵连乘且矩阵行列数分别是96*6464*8282*3636*3838*6161*90的结果如下:

 

 

2. 6个矩阵连乘且矩阵行列数分别是39*8585*6565*4949*8282*4545*68的结果如下:

 

3. 20个矩阵连乘且矩阵行列数分别是25*6565*3838*4949*3031*5151*62、   62*4848*5858*9292*5454*6868*6060*2525*3434*5858*4747*6868*6060*3838*31的结果如下:

 

算法实验--矩阵连乘