您的位置:首页 > 其它

动态规划之矩阵连乘

2015-04-05 13:51 260 查看
问题介绍:

给定n个矩阵{A1,A2,A3......An},其中Ai与Ai+1是可乘的,i=1,2......n-1.考察n个矩阵连乘积的最小次数,即以最少的计算量来求得最终结果。

矩阵连乘性质分析:

1.假设ra,ca和rb,cb表示矩阵A和B的行数与列数,则AxB=ra*ca*cb,因为相邻连乘的矩阵必有ca=rb

2.同一连乘矩阵由不同连乘顺序,所以计算量不一样,但最终结果是一样

例如:矩阵连乘积A1A2A3A4A5可以有一下五种不同的计算次序
(A1(A2(A3A4))),(A1((A2A3)A4)),((A1A2)(A3A4)),((A1(A2A3))A4),(((A1A2)A3)A4)

现在我们的目的是要找到其中计算量最小的连乘方式,

建立模型分析:

1.将矩阵连乘积AiAi+1......Aj简记为A[i,j]

2.假设计算次序在Ak和Ak+1之间断开,i<=k<j,则先计算A[i,k]和A[k+1,j]然后将计算结果相乘得到A[i,j],故总计算量为A[i,k]的计算量加上A[k+1,j]的计算量,再加上

A[i,k]和A[k+1,j]相乘的计算量。

最优子结构:

假设用m[i][j]表示A[i,j]

1.要得到A[i,j]的最小值,由于i<=k<j,所以我们要找到k的取值令A[i,j]最小时的情况,即

m[i][j]=min{m[i][k]+m[k+1][j]+pi-1*pk*pj} i<=k<j


m[i][j]=0 i=j

同理m[i][k]和m[k+1][j]也取其最优断开处得到的最小值,这样一步步到最后,当i=1,j=n时,由于我们每一步取得都是最小值,那么总体上来说,我们得到的当然也是 最小值。

因此,矩阵连乘的计算次序问题的最优解包含着子问题的最优解,这种性质成为最优子结构性质。

算法分析:

1.对于动态规划算法可以看出,由于前一步的值得到了保存,避免了重复计算。时间复杂度最多为O(n3)

2.对于直接递归算法,由于计算过的值又被重复计算,造成时间复杂度猛增。

T(n)=1+

(T(k)+T(n-k)+1) n>1

可以计算出T(n)>2的n-1次方,立方级的复杂度可想而知了,

3.备忘录法同动态规划法一样,由于保存了其中间值,复杂度从2n降为n3

#include<iostream>
using namespace std;
#define MAXNUM 20
int p[MAXNUM];
int s[MAXNUM][MAXNUM];
int m[MAXNUM][MAXNUM];

//动态规划法
void MatrixChain(int *p,int n,int m[][MAXNUM],int s[][MAXNUM])
{
	for(int i=1;i<=n;i++) m[i][i]=0;
	for(int r=2;r<=n;r++)   //r表示矩阵间隔多少位置
		for(int i=1;i<=n-r+1;i++)
		{
			int j=i+r-1;
			m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];
			s[i][j]=i;
			for(int k=i+1;k<j;k++)
			{
				int 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<<"m["<<i<<"]["<<j<<"]"<<m[i][j]<<endl;
		}
}

//递归算法直接求解
int RecurMatrix(int i,int j)
{
	if(i==j)
		return 0;
	int u=RecurMatrix(i,i)+RecurMatrix(i+1,j)+p[i-1]*p[i]*p[j];
	s[i][j]=i;
	for(int k=i+1;k<j;k++)
	{
		int t=RecurMatrix(i,k)+RecurMatrix(k+1,j)+p[i-1]*p[k]*p[j];
		if(t<u)
		{
			u=t;
			s[i][j]=k;
		}
	}
	return u;
}

//备忘录法
int RecurMatrixSave(int i,int j)
{
	if(m[i][j]>0)
		return m[i][j];
	if(i==j)
		return 0;
	int u=RecurMatrix(i,i)+RecurMatrix(i+1,j)+p[i-1]*p[i]*p[j];
	s[i][j]=i;
	for(int k=i+1;k<j;k++)
	{
		int t=RecurMatrix(i,k)+RecurMatrix(k+1,j)+p[i-1]*p[k]*p[j];
		if(t<u)
		{
			u=t;
			s[i][j]=k;
		}
	}
	m[i][j]=u;
	return u;
}

void TraceBack(int i,int j,int  s[][MAXNUM])
{
	if(i==j) {cout<<i;return;}
	cout<<"(";
	TraceBack(i,s[i][j],s);
	TraceBack(s[i][j]+1,j,s);
	cout<<")";		
}
int main()
{
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		for(int i=0;i<n;i++)
		{
			cout<<"请输入第"<<i<<"个维度"<<endl;
			scanf("%d",&p[i]);
		}
		MatrixChain(p,n-1,m,s);
		TraceBack(1,n-1,s);
		cout<<endl;
		RecurMatrixSave(1,n-1);
		TraceBack(1,n-1,s);
		cout<<endl;
		RecurMatrix(1,n-1);
		TraceBack(1,n-1,s);
	}

	return 0;
}




算法分析:
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: