算法设计——矩阵连乘(动态规划)

问题

给定定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);
}
  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值