动态规划:矩阵连乘问题

[ Description]
给定n个矩阵A1, A2,… An,其中,A;与Aj+1是可乘的,i=1, 2, . n-1。确定矩阵连乘的运算次序,使计算这n个矩阵的连乘积A1A—An时总的元素乘法次数达到最少,例如,3个矩阵A1, A2, A3,阶分别为10X100、100X5、 5x50,计算连乘积A.A.A.时按(A142) A3所需的元素乘法次数达到最少,为7500次。
[Input]
有若干种案例,每种两行,第一行是一个非负整数n,表示矩阵的个数,n=0 表示结束。接着有n行,每行为两个正整数,表示矩阵的维数。
[Output]
对应输出最小的乘法次数。
[Sample Input】
4
5 20
20 50
50 1
1 100
0
[Sample Output】
1600

分析:
二.问题分析

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

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

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

(2).矩阵连乘积A是完全加括号的,则A可以表示为2个完全加括号的矩阵连乘积B和C的乘积并加括号,及A=(BC)
举个例子,矩阵连乘积A1A2A3A4A5,可以有5种不同的完全加括号方式:
(A1(A2(A3A4))),(A1((A2A3)A4)),((A1A2)(A3A4)),((A1(A2A3))A4),(((A1A2)A3)A4)
每一种完全加括号的方式对应一种矩阵连乘积的计算次序,而矩阵连乘积的计算次序与其计算量有密切的关系,即与矩阵的行和列有关。
补充一下数学知识,矩阵A与矩阵B可乘的条件为矩阵A的列数等于矩阵B的行数,例如,若A是一个pq的矩阵,B是一个qr的矩阵,则其乘积C=AB是一个p*r的矩阵。

源码如下:

#include<iostream>
#include<algorithm>
using namespace std;

#define max 255

int a[max],m[max][max];

int Getmin(int i,int j)
{
	int min,n;
	if(m[i][j]>=0)
		return m[i][j];
	if(i==j)
		return 0;
	if(i==j-1)
	{
		m[i][j]=a[i]*a[i+1]*a[i+2];
		return m[i][j];
	}

	min=Getmin(i,i)+Getmin(i+1,j)+a[i]*a[i+1]*a[j+1];
	for(int k=i+1;k<j;k++)
	{
		n=Getmin(i,k)+Getmin(k+1,j)+a[i]*a[k+1]*a[j+1];
		if(n<min)
			min=n;
	}
	m[i][j]=min;
	return min;
}

int main()
{
	int n,i,end;
	while(cin>>n)
	{
		if(n==0)
			break;
		for(i=1;i<=n;i++)
			cin>>a[i]>>end;
		a[i]=end;//要给最后一个n+1的那个数组赋值
		memset(m,-1,sizeof(m));//初始化
		cout<<Getmin(1,n)<<endl<<endl;//计算获取乘法次数最小的次数
	}
	return 1;
}

相关题目 POJ1651
相关源代码:

#include<iostream>
#include<algorithm>
using namespace std;

int a[255],m[255][255],n;//数组代表每个卡片的数字 另一个代表矩阵相乘 n代表有几张卡牌

int Getmin()
{
	int len;
	for(len=1;len<n;len++)//len可以说是代表计算的长度
	{
		int i,j,k;
		for(i=1,j=len+1;j<n;i++,j++)//1 3
		{
			int min=999999999;
			for(k=i;k<j;k++)
			{
				int sum=m[i][k]+m[k+1][j]+a[i-1]*a[k]*a[j];//11 23 0 1 3
				if(sum<min)
					min=sum;
			}
			m[i][j]=min;
		}		
	}
	return m[1][n-1];//计算了所有 返回想要的值
}

int main()
{
	while(cin>>n)
	{
		if(n==0)
			break;
		for(int i=0;i<n;i++)
			cin>>a[i];
		memset(m,0,sizeof(m));
		cout<<Getmin()<<endl<<endl;	
	}
	return 1;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值