问题描述:给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2…,n-1。如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。
一 分析最优解的性质与结构
最优解也就是计算A[1:n]的最优次序,可以假设这个最优解在第k处断开,1<=k<j,则A[1:j]是最优的,那么A[1,k]和A[k+1:j]也是相应矩阵连乘的最优解。
关键在于矩阵乘积计算次序问题的最优解包含着其子问题的最优解,这种性质是最优子结构性质。
二 建立递归关系
其中m[i][j]表示最少数乘次数,也就是构建最优解的代价。
其中pi-1pkpj表示前两部分相乘的代价。(Ai的维数可以表示为pi-1*pi).
三 计算最优值并解决子问题重叠问题
子问题重叠:
根据以上递归中,可以知道有些子问题例如m[1,2]被不同的子问题包含,可能被计算多次。
解决办法:
根据递归形式以自底向上的方式进行计算,在计算过程中保存已解决的子问题答案,从而避免重复计算。
具体:
数组m[n][n]存取最优值,数组s[n][n]表示分割位置,按照递增的方式逐步填写子问题的解,也就是先计算长度为2的所有矩阵链的解,然后计算长度3的矩阵链,直到长度n。
m[i][i]=0(矩阵链长为1)
m[i][i+1] (链长为2)
…
所以当计算m[i][j]时只用到了m[i][k]和m[k+1][j]。
四 构造最优解
从s[1][n]中可知,最优加括号方式应为(A[1:s[1][n])(A[s[1][n]+1:n)。
A[i:s[1][n])的最优加括号方式为A[1:s[1][s[1][n]]])(A[s[1][s[1][n]]]+1:s[1][n]])…
最终可以构造原问题的最优解。
#include <stdio.h>
#include <stdlib.h>
void MatrixChain(int p[6],int n,int m[][7],int s[][7])
{
int r=0,i=0,j=0,k=0,t=0;
for(i=1;i<=n;i++)
m[i][i]==0;
for(r=2;r<=n;r++)
for(i=1;i<=n-r+1;i++)//n-r+1表示保证有r个矩阵相乘
{
j=i+r-1;//当r=3时 有三个矩阵 但j=i+2,所以需要-1
m[i][j]=m[i][i]+m[i+1][j]+p[i-1]*p[i]*p[j];//默认在初始下标之后断开,得到初始值
s[i][j]=i;
for(k=i+1;k<j;k++)
{
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;
}
}
}
}
void TrackBack(int i,int j, int s[][7])
{
if(i==j) return;
TrackBack(i,s[i][j],s);//递归第一次断开之前
TrackBack(s[i][j]+1,j,s);
printf("A%d",i);
printf(" and A%d",j);
printf("\n");
}
int main()
{
int n=6;
int p[]={30,35,15,5,10,20,25};
int s[7][7]={0};
int m[7][7]={0};
MatrixChain(p,n,m,s);
TrackBack(1,n,s);
}
结果