目的
由于n个矩阵联乘时,计算次序影响着计算量(数乘的次数),所以要找到一种加括号的方式使得依次计算次序计算矩阵联乘需要的数乘次数最少。
实现过程
加括号的过程可以看作对这组矩阵加断点将矩阵链断开,所以假设在
A
k
\ A_k
Ak和
A
k
+
1
\ A_{k+1}
Ak+1之间断开,此时,将原矩阵链分为了
A
[
1
:
k
]
\ A[1:k]
A[1:k]和
A
[
k
+
1
:
n
]
\ A[k+1:n]
A[k+1:n]两部分,想要最后整体达到最优,那么分开的两段也要达到最优。且分段后
A
[
i
:
n
]
\ A[i:n]
A[i:n] 的最小数乘数为
A
[
1
:
k
]
\ A[1:k]
A[1:k]的计算量加上
A
[
k
+
1
:
n
]
\ A[k+1:n]
A[k+1:n]的计算量再加上
A
[
1
:
k
]
\ A[1:k]
A[1:k]和
A
[
k
+
1
:
n
]
\ A[k+1:n]
A[k+1:n]相乘的计算量。
由此递归的定义出最少
A
[
i
:
j
]
\ A[i:j]
A[i:j]段的最小数乘数为
在代码实现的过程中利用了递归的重叠子问题性质,对于反复计算的子问题,自底向上计算,将答案保存,后面再需要直接查找即可。
代码
r表示矩阵联乘规模,i表示最大可起始点,m最优值数组,s最优断开位置的数组。
void matrixchain(int *p,int n,int **m,int **s)
{
for(int i=1;i<=n;i++)
{
m[i][i]=0;
}
for(int r=2;r<=n;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];//Ai的维数时是pi-1,pi
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[i]*p[j];
if(t<m[i][j])
{
m[i][j]=t;
s[i][j]=k;
}
}
}
}
}
void traceback(int i,int j,int **s)
{
if(i==j)
return;
traceback(i,s[i][j],s);
traceback(s[i][j]+1,j,s);
cout<<"A ["<<i<<","<<s[i][j]<<"]";
cout<<"and A ["<<s[i][j]+1<<","<<j<<"]"<<endl;
}