设有一个矩阵链A1*A2*A3,其维度为30*35,35*15,15*5。不同的结合性,需要的矩阵乘法数量不同,m[(A1*A2)*A3] = 30*35*15+0+30*15*5 = 18000,而m[A1*(A2*A3)] = 0+35*15*5+30*35*5 = 7875。所以,结合性在A1后面划分,运算量最小。
对于矩阵链A1*A2*A3*......*An,假设矩阵都是相容的,如果用递归的方法解,其复杂度为Ω(2^n)(有证明),而动态规划的复杂度为Ω(n^3)+seta(n^2)。
动态规划算法的四步:1、描述最优解的结构:对于矩阵链A(i)A(i+1)......A(j),若存在i<=k<j,使得A(i)A(i+1)......A(k)、A(k+1)......A(j)、两个子结构之积,这三者代价之和最小,那么k为其中一个划分。同时两个子结构为最优子结构。2、定义最优解的值:m[i,j] = min{m[i,k]+m[k+1,j]+p(i-1)pkpj} (i<j,i<=k<j)和m[i,j] = 0 (i=j)。3、由低向上计算最优解的值:对于矩阵链A1*A2*A3*......*An,自左往右,首先计算步长为1的最优解,步长依次递增,直到求步长为n-1的最优解。其中m[i,j]存最优解代价,s[i,j]存放最优解的划分位置。4、根据S[i,j]就能够求的具体的划分了。
伪代码:
图1
下面是具体代码实现:
#include<stdio.h>
int PrintDivi(int (*p)[6], int start, int end)
{
int Divi;
Divi = p[start][end];
if(start == end)
printf("A%d",start+1);
else
{
printf("(");
PrintDivi(p, start, Divi);
PrintDivi(p, Divi+1, end);
printf(")");
}
}
int main(void)
{
int l,i,j,k,temp;
int p[7] = {30,35,15,5,10,20,25};
int m[6][6],s[6][6];
for(i=0;i<6;i++)
{
m[i][i] = 0;
}
for(l=2;l<=6;l++)
for(i=0;i<6-l+1;i++)
{
j=i+l-1;
m[i][j] = 0x7fffffff;
for(k=i;k<j;k++)
{
temp = m[i][k]+m[k+1][j]+p[i]*p[k+1]*p[j+1];
if(temp<m[i][j])
{
m[i][j] = temp;
s[i][j] = k;
}
}
}
PrintDivi(s, 0, 5);
return 0;
}
参考书目:《算法导论》第二版