问题
给定定n个矩阵 {A1,A2,A3…An}, 其中 Ai与Ai+1 是可乘的, 求矩阵连乘的最少计算乘法次数的顺序。
分析
为什么会有不同次数的乘法?
由于矩阵A(mn)B(nr)乘法次数为mnr
不同矩阵计算顺序会导致不同的计算次数
举个栗子来说明
假如有6个矩阵,矩阵信息如下
用m[i,j]记录第i个到第j个矩阵的乘法次数
如A1到A6的乘法可划分为(A1A2A3)(A4A5A6)
按照这个顺序m[1,6]=m[1,3]+m[4,6]+P[0]P[3]P[6]
为什么会有P[0]P[3]P[6]呢?
因为m[1,3]记录的是(A1A2A3)(看做一个矩阵行为P[0]列为P[3])的乘法次数
m[4,6]记录的是(A4A5A6)(看做一个矩阵行为P[3]列为P[6])的乘法次数
那么A1到A6的乘法还需要按照两个矩阵的乘法相乘,这一步仍要记录乘法次数
故存在P[0]P[3]P[6]
那我们要怎么找到最少次数乘法的顺序呢
m[1,6]有5种可能
1.A1(A2A3A4A5A6)
2. (A1A2)(A3A4A5A6)
3. (A1A2A3)(A4A5A6)
4. (A1A2A3A4)(A5A6)
5. (A1A2A3A4A5)A6
计算次序:
第一次即计算m[1,2]m[2,3]m[3,4]m[4,5]m[5,6]
第二次计算m[1,3]m[2,4]m[3,5]m[4,6]
第三次计算m[1,4]m[2,5]m[3,6]
第四次计算m[1,5]m[2,6]
第五次计算m[1,6]
即得到最终需要的答案
通过归纳我们发现
1.n个矩阵共做n-1次循环
2.每次增加一个单位的长度
3.每轮循环结束的行从最底行每次向上推一行
过程
①初始化主对角线为0
②按计算顺序进行计算比较,按照递归定义
得到下图乘法次数
其中用m[3][5]举例
m[3][5]=m[3][3]+m[4][5]+p[2]p[3]p[5]
m[3][5]=m[3][4]+m[5][5]+p[2]p[4]p[5]
求得小的值保存
我们要求的是矩阵相乘循序,那我们需要得到矩阵断开的位置,用s来保存s[i][j]中记录了矩阵链应从哪个位置断开
如s[1][6]=3,即A[1:6]从3的位置断开
那么上面的例子我们得到的s图如下
我们可根据s图对矩阵的划分进行输出
代码实现
以上面的数据为例
#include<stdio.h>
#define N 101
void road(int i,int j,int s[][N]){//打印划分
if(i==j) return ;
road(i,s[i][j],s);//划分左边
road(s[i][j]+1,j,s);//划分右边
printf("A%d,%d andA%d,%d\n",i,s[i][j],s[i][j]+1,j);
}
void fun(int p[],int n,int m[][N],int s[][N]){//p储存n个矩阵的行列数,p有n+1个数据,m储存i到j的最小乘法次数,s保存断点位置
int i,j,k,q;
for(i=1;i<=n;i++) m[i][i]=0;//对角线0化
for(i=2;i<=n;i++){//区间长度
for(j=1;j<=n-i+1;j++){//行,每轮循环结束的行每次向上推一行
k=i+j-1;// 右边下标
m[j][k]=m[j+1][k]+p[j-1]*p[j]*p[k];//计算 ,如m[2,5]=m[3,5]+p[1]p[2]p[5]
s[j][k]=j;//划分区间
for(q=j+1;q<k;q++){//上三角
int t=m[j][q]+m[q+1][k]+p[j-1]*p[q]*p[k];//计算每一个
if(t<m[j][k]){//寻找小的值
m[j][k]=t;//更新最小值
s[j][k]=q;//保存断点位置
}
}
}
}
printf("最少次数%d\n",m[1][n]);
}
int main()
{
int i;
int p[N]={30,35,15,5,10,20,25},m[N][N],s[N][N];
fun(p,6,m,s);
road(1,6,s);
}