分析:
如果一个矩阵连乘积的计算次序已经确定,也就是说该连乘积已经完全加括号,则可依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。完全加括号的矩阵连乘积可递归的定义为:
①单个矩阵是完全加括号的;
②矩阵连乘积A是完全加括号的,则A可表示为2个完全加括矩阵连乘积B和C的乘积并加括号,即
下面考虑运用动态规划法解矩阵连乘积的最优计算次序问题。按以下几个步骤进行:
程序实现
#include <stdio.h>
#include <stdlib.h>
#define N 20
void MatrixChain(int p[N],int n,int m[N][N],int s[N][N])
//m[N][N]是矩阵相乘的最优次数矩阵,n是矩阵数
//s[N][N]是矩阵相乘最优断开位置矩阵,p[N]是默认相乘的矩阵
{
for(int i=1;i<=n;i++)
{
m[i][i]=0; //m[i][i]只有一个矩阵,所以相乘次数为0,即m[i][i]=0
}
for(int r=2;r<=n;r++)//至少是2个矩阵参与连乘,最多有n个
{
//公式i<j所以次数矩阵是一个上三角矩阵,遍历所有上三角位置
for(int i=1;i<=n-r+1;i++)//n-r+1表示保证有r个矩阵相乘
{
int j=i+r-1;
m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j]; //拿到从i到j矩阵连乘的次数
s[i][j]=i; //拿到矩阵断开的位置值
//寻找加括号不同,矩阵连乘次数的最小值,修改m[N][N],和断开的位置s[N][N]
for(int k=i+1;k<j;k++)
{
//公式i<j时得到的矩阵连乘的次数最优值
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;//修改m[N][N],和断开的位置s[N][N]
s[i][j]=k;
}
}
}
}
}
int main(void)
{
int n,n1,m1,i,j=2; //n是矩阵个数,n1 m1是矩阵的行和列
int p[N]={0}; //存储矩阵的行和列数组
int m[N][N]={0}; //存储矩阵与矩阵相乘的最小次数
int s[N][N]={0}; //存储矩阵与矩阵相乘断开的位置
//获得矩阵规模
printf("请输入矩阵个数:");
scanf("%d",&n);
//依次输入n个矩阵的行列值
for(i=1;i<=n;i++){
printf("请输入第%d个矩阵的行和列(n1 m1):",i);
scanf("%d %d",&n1,&m1);
//把第一个矩阵行列值依次赋给数组p[0],p[1]
if(i==1)
{
p[0]=n1;
p[1]=m1;
}
//把矩阵的列值依次赋给数组p[n]
else{
p[j++]=m1;
}
}
printf("\n记录矩阵行和列:\n");
for(i=0;i<=n;i++){
printf("%d ",p[i]);
}
printf("\n");
//通过MatrixChain函数得出m[N][N],s[N][N]
MatrixChain(p,n,m,s);
//遍历输出最优次数矩阵
printf("\n矩阵相乘的最小次数矩阵为:\n");
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
printf("%d\t",m[i][j]);
}
printf("\n");
}
//遍历输出最优断开位置矩阵
printf("\n矩阵相乘断开的位置矩阵为:\n");
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
printf("%d\t",s[i][j]);
}
printf("\n");
}
//输出矩阵最小相乘次数
printf("矩阵最小相乘次数为:%d\n",m[1][n]);
return 0;
}
实验结果分析: