欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

算法分析与设计----矩阵连乘

程序员文章站 2022-07-03 14:29:11
...

给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2…,n-1。如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。例如,给定三个连乘矩阵{A1,A2,A3}的维数分别是10 * 100,100 * 5和5 * 50,采用(A1A2)A3,乘法次数为10 * 100 * 5 + 10 * 5 * 50=7500次,而采用A1(A2A3),乘法次数为100550+1010050=75000次乘法,显然,最好的次序是(A1A2)A3,乘法次数为7500次。

矩阵连乘问题,需要用动态规划来解决,为每个矩阵编号:
算法分析与设计----矩阵连乘
输入矩阵:
算法分析与设计----矩阵连乘
用p数组来表示矩阵,因为前一个矩阵的列是后一个矩阵的行,所以对于n个矩阵来讲只需输入n+1个数。1号矩阵 = p[0] * p[1] , 2号矩阵 = p[1] * p[2],…
我们假设1号矩阵到3号矩阵已经乘完,那么得到了一个10 * 25 的矩阵(10 * 50 50 * 20 20 * 25得到的最后矩阵为10 * 25 ),假设4号矩阵到5号矩阵也已经乘完,得到了25 * 100 的矩阵,那如果这两个矩阵相乘,需要多少次呢?矩阵的乘法是一行乘一列这样乘的,所以需要10 * 25 * 100 = 25000次乘法运算。10是一号矩阵的行,25是3号矩阵的列,100是5号矩阵的列,我们将矩阵乘法的最少次数保存到m[][]二维数组中,那么m[1][5]就表示1号矩阵乘到5号矩阵需要的次数,拿上面的例子来说,m[1][5]=m[1][3]+m[4][5]+p[0]*p[3]*p[5],意思是说 1号到5号矩阵乘法的次数=1号矩阵乘到3号矩阵的次数 + 4号矩阵乘到5号矩阵的次数 + 这两个乘法的次数(1号矩阵行 * 3号矩阵列 * 5号矩阵行 p[0]*p[3]*p[5]),而对于m[1][3]来说,也是类似于上面的求法,求出最小值。由此可以得出动态转移方程:
当 i = j 时:
m[i][j] = 0
当 i < j 时:
m[i][j] = min{ m[i][k] + m[k+1][j] + pi-1 * pk * pj } , i<=k<j

#include<bits/stdc++.h>
using namespace std;
int p[100];
int m[50][50];
int s[50][50];
void print(int i,int j)
{
	if(i == j)
	{
		printf("A[%d]",i) ;
		return ;
	}	
	printf("(");
	print(i,s[i][j]);
	print(s[i][j]+1,j);
	printf(")");
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i = 0;i<=n;i++)
		scanf("%d",&p[i]);
	for(int step=2;step<=n;step++) //链长 
		for(int left=1;left<=n-step+1;left++)
		{
			int right = left+step-1;
			m[left][right] = m[left+1][right]+p[left-1]*p[left]*p[right];
			s[left][right] = left;
			for(int k=left+1;k<right;k++)
				if(m[left][k]+m[k+1][right]+p[left-1]*p[k]*p[right]<m[left][right])
					m[left][right] = m[left][k]+m[k+1][right]+p[left-1]*p[k]*p[right],s[left][right] = k;
		}
	printf("%d\n",m[1][n]);
	print(1,n);
}