问题介绍:
给定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.同一连乘矩阵由不同连乘顺序,所以计算量不一样,但最终结果是一样
(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;
}
算法分析: