矩阵连乘遵循乘法的结合律,不同的结合方式会导致不同数量级的相乘次数,一些结合方式会导致相乘的效率极大降低,所以我们采取动态规划的方式来寻求一种最佳的结合方式。
比如:三个矩阵连乘A1xA2xA3有两种结合方式:
由上可知,不同结合方式会有不同的相乘次数,并且差距较大!
#include<stdio.h>
#include<malloc.h>
#include<limits.h>//包含整型数据的最大值
//#define INT_MAX 2147483647
int **s;//定义为全局变量,否则不易同时返回二位数组m和二维数组s
int **MatrixChainOrder(int p[],int length)//int**表示返回类型为二维数组
{
int n=length-1;
int **m;
int i,j,l,k,q;
m=(int **)malloc(sizeof(int *)*(n+1));
for(i=0;i<=n;i++)
m[i]=(int *)malloc(sizeof(int)*(n+1));
s=(int **)malloc(sizeof(int *)*(n+1));
for(i=0;i<=n;i++)
s[i]=(int *)malloc(sizeof(int)*(n+1));
for(i=1;i<=n;i++)
m[i][i]=0;
for(l=2;l<=n;l++)//l表示矩阵连乘的个数
{
for(i=1;i<=n-l+1;i++)
{
j=i+l-1;
m[i][j]=INT_MAX;
for(k=i;k<=j-1;k++)
{
q=m[i][k]+m[k+1][j]+p[i-1]*p[j]*p[k];
if(q<m[i][j])
{
m[i][j]=q;
s[i][j]=k;
}
}
}
}
return m;
}
int Print_Optional_Parens(int **s,int i,int j)
{
if(i == j)
printf("A%d",i);
else
{
printf("(");
Print_Optional_Parens(s,i,s[i][j]);
Print_Optional_Parens(s,s[i][j]+1,j);
printf(")");
}
}
int main( )
{
int p[4]={2,5,7,9};//3个矩阵
int **m;
int i,j;
m=(int **)malloc(sizeof(int *)*4);
for(i=0;i<4;i++)
m[i]=(int *)malloc(sizeof(int)*4);
m=MatrixChainOrder(p,4);
printf("相乘次数最少的为:%d\n",m[1][3]);
for(i=1;i<=3;i++)
{
for(j=1;j<=3;j++)
if(i>j)
printf("%5d ",0);
else
printf("%5d ",m[i][j]);
printf("\n");
}
printf("最佳相乘方式:");
Print_Optional_Parens(s,1,3);
return 0;
}
运行实例为三个矩阵连乘,所以存储矩规模的p数组的长度为4,最后的结果应该为m[1][3]表示A1xA2xA3的最佳结果,m[i][j]中存储的就是从Ai到Aj连乘的最少次数,s[i][j]中存储的是Ai到Aj连乘的最少次数分界线,记录下来用于输出。
运行结果如下:
第一次原创博客,希望可以对大家有所帮助!
小白记录点滴,欢迎指正!