矩阵连乘

问题:给定n个矩阵:A1,A2,...,An,其中Ai与Ai+1是可乘的,i=1,2...,n-1。确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。输入数据为矩阵个数和每个矩阵规模,输出结果为计算矩阵连乘积的计算次序和最少数乘次数。

分析:由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则可以依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。

       完全加括号的矩阵连乘积可递归地定义为:

     (1)单个矩阵是完全加括号的;

     (2)矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的矩阵连乘积B和C的乘积并加括号,即A=(BC)

       例如,矩阵连乘积A1A2A3A4有5种不同的完全加括号的方式:(A1(A2(A3A4))),(A1((A2A3)A4)),((A1A2)(A3A4)),((A1(A2A3))A4),(((A1A2)A3)A4)。每一种完全加括号的方式对应于一个矩阵连乘积的计算次序,这决定着作乘积所需要的计算量。

Ai....AkAk+1...Aj一组矩阵,ai-1*ak,ak*aj,的递推公式为

0;i=j

f(i,j)=

min(k){f(i,k)+f(k+1,j)+ai-1*ak*aj};i<j,k>=i,k<=j

递归法:

int a[m+1]={30,35,15,5,10,20,25};
int b[m+1][m+1];
int f(int i,int j){
	int minvalue;
	int k,temp;
	if(i==j)
		return 0;
	minvalue=f(i+1,j)+a[i-1]*a[i]*a[j];
	b[i][j]=i;
	for(k=i+1;k<j;k++){
		temp=f(i,k)+f(k+1,j)+a[i-1]*a[k]*a[j];
		if(minvalue>temp){
			minvalue=temp;
			b[i][j]=k;
		}
	}
	return minvalue;
}
void traceback(int i,int j){
	if(i==j)
		return ;
	traceback(i,b[i][j]);
	traceback(b[i][j]+1,j);
	printf("A[%d-%d]*A[%d-%d]\n",i,b[i][j],b[i][j]+1,j);
}
int main(){
	printf("%d\n",f(1,m));
	traceback(1,m);
	return 0;
}

动态规划法:

int a[m+1]={30,35,15,5,10,20,25};
int b[m+1][m+1];
int number[m+1][m+1]={0};
void traceback(int i,int j){
	if(i==j)
		return ;
	traceback(i,b[i][j]);
	traceback(b[i][j]+1,j);
	printf("A[%d-%d]*A[%d-%d]\n",i,b[i][j],b[i][j]+1,j);
}
int main(){
	int r;//参与矩阵运算次数
	int i,j,k,temp;
	for(r=2;r<m+1;r++){
		for(i=1;i<=m-r+1;i++){
			j=i+r-1;
			b[i][j]=i;
			number[i][j]=number[i+1][j]+a[i-1]*a[i]*a[j];
			for(k=i+1;k<j;k++){
				temp=number[i][k]+number[k+1][j]+a[i-1]*a[k]*a[j];
				if(number[i][j]>temp){
					number[i][j]=temp;
					b[i][j]=k;
				}
			}
		}
	}
	printf("%d\n",number[1][m]);
	traceback(1,m);
	return 0; 
} 

备忘录法:

int a[m+1]={30,35,15,5,10,20,25};
int b[m+1][m+1];
int number[m+1][m+1];
int f(int i,int j){
	int minvalue;
	int k,temp;
	if(i==j)
		return 0;
	if(number[i][j]>0)
		return number[i][j];
	minvalue=f(i+1,j)+a[i-1]*a[i]*a[j];
	b[i][j]=i;
	for(k=i+1;k<j;k++){
		temp=f(i,k)+f(k+1,j)+a[i-1]*a[k]*a[j];
		if(minvalue>temp){
			minvalue=temp;
			b[i][j]=k;
		}
	}
	number[i][j]=minvalue;
	return minvalue;
}
void traceback(int i,int j){
	if(i==j)
		return ;
	traceback(i,b[i][j]);
	traceback(b[i][j]+1,j);
	printf("A[%d-%d]*A[%d-%d]\n",i,b[i][j],b[i][j]+1,j);
}
int main(){
	printf("%d\n",f(1,m));
	traceback(1,m);
	return 0;
}




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值