矩阵连乘积:最优乘法次数(C语言)

题目: 确定n个矩阵连乘积 A1A2A3…An 的计算次序,使得按照这一次序计算矩阵连乘积,需要的"数乘"次数最小。

  • 这个问题满足动态规划的条件
  • 矩阵乘法满足结合律
  • 两个矩阵相乘,要满足左边矩阵的列数 = 右边矩阵的行数
  • 两个矩阵相乘,计算量为:左边矩阵的行数 乘以 左边矩阵的列数(即:右边矩阵的行数)乘以 右边矩阵的列数
  • 问题实际上不是执行乘法,而只是决定所涉及的矩阵乘法的顺序

思路:
将矩阵连乘积记为 { P(i-1), Pi, P(i+1), … , Pk, … , Pj } :

  • P(i-1) 是矩阵Ai的行数
  • Pi 是矩阵Ai的列数,也是矩阵A(i+1)的行数
  • P(i+1) 是矩阵矩阵A(i+1)的列数
  • 即:{P(i-1), Pi, P(i+1)}表示的是两个矩阵AiA(i+1)相乘

假设 矩阵连乘式A[i:j] 的最优计算次序的最后一次相乘在矩阵Ak和矩阵A(k+1)之间断开,
k的位置只有j-1种可能
计算量为:A[i:k]的最优计算量 + A[k+1:j]的最优计算量 + 最后乘法运算留下的两个矩阵相乘的计算量(如下图)

在这里插入图片描述

递归算法(使用备忘录:解决重叠子问题,提高算法效率):

#include<iostream>

using namespace std;
#define MaxSize 20

void MatrixChain(int *p, int n, int m[][MaxSize], int s[][MaxSize]){   //算最优乘法次数
	int i,j,r,k;
	int t; //t为中间量 
	for(i = 1; i <= n; i++){ 
		m[i][i]= 0;          //将单一矩阵都置为0,因为会在如上图中的算式出现,所以是置为0 
	}
	
	for(r = 2; r <= n; r++){          //r表示连乘矩阵中矩阵的个数 
		for(i = 1; i <= n-r+1; i++){  //i表示连乘矩阵的第一个 
			j = i + r - 1;            //j表示连乘矩阵的最后一个
			m[i][j] = m[i+1][j] + p[i-1] * p[i] * p[j];     //此处i赋给k(参考上图中算式)
			s[i][j] = i; 
			for(k = i+1; k < j; k++){
				t =  m[i][k] + m[k+1][j] + p[i-1] * p[k] * p[j];     //(上图中算式)
				if(t < m[i][j]){
					m[i][j] = t;
					s[i][j] = k;
				}
			} 
		}
	} 
	cout<<endl<<"最优乘法次数:"<<m[1][n]<<endl;
}

void TraceBack(int i,int j, int s[][MaxSize]){   //最优乘法路径
	if(i < j-1){
		TraceBack(i,s[i][j],s);
		TraceBack(s[i][j]+1,j,s);
		cout<<"Matrix A"<<i<<" , "<<s[i][j]<<"and A"<<s[i][j]+1<<" , "<<j<<endl; 
	}
} 

int main(){
	int m[MaxSize][MaxSize],      //m[i][j]记录从i到j所需最少连乘数 
		s[MaxSize][MaxSize];      //s[i][j]对应于m[i][j]断开位置 
		
	int p[MaxSize]; //存放矩阵的行数,列数 	
	int n;	
	do{
		cout<<"请输入矩阵连乘的矩阵个数(2到20)n = ";
		cin>>n;
	}while(n < 2 || n > 20);
	
	cout<<"请依次输入n个矩阵的行数及最后一个矩阵的列数(输入n+1个数):" <<endl;
	for(int i = 0; i < n+1; i++){
		cin>>p[i];
	} 
	
	MatrixChain(p,n,m,s); 
	TraceBack(1,n,s); 	
}

猜你喜欢

转载自blog.csdn.net/Zhangguohao666/article/details/83413483