矩阵链乘法
n个矩阵相乘,A1A2...An,试着找到一种相乘顺序,使得整个相乘的过程中所做的标量乘法次数最少,即相乘的代价最小。
问题分析:
记矩阵Ai的行列分别为Pi-1和Pi,那么A1*A2所做的乘法的次数为P0*P1*P2
A1A2...An的最小相乘代价为f(1,n),Ai...Aj的最小相乘代价为f(i,j)
则 f(1,n) = min{f(1,k)+f(k+1,n)+P0*Pk*Pn} k=1...n-1
f(i,i)=0 f(i,i+1)=Pi-1*Pi*Pi+1
So 可以由此产生递归式
1 Recursive_Matrix_Multiply(p, i, j)
2 {
3 if(i==j)
4 return 0;
5 f[i][j] = max_int;
6 for(k=i;k<j;k++)
7 {
8 q=Recursive_Matrix_Multiply(p,i,k)+Recursive_Matrix_Multiply(p,k+1,j)+p[i-1]*p[k]*p[j];
9 if(q<f[i][j])
10 {
11 f[i][j]=q;
12 s[i][j]=k;
13 }
14 }
15 return f[i][j];
16 }
其中s[i][j]记录的是Ai...Aj相乘的最小代价的分割点,即先计算Ai...Ak,再计算Ak+1...Aj,然后再将结果相乘,Ai...Aj的相乘代价最小
递归的解法看起来思路清晰,但时间复杂度太高
若记n个矩阵的时间复杂度为T(n),则T(n)=∑k=1..n-1{T(k) + T(n-k) + c}, 可以推断T(n)>=2n
分析递归的过程可以发现,有很多子问题被重复计算过了,比如计算A1...A3的过程中需要A2A3,在A1...Aj,j>3的过程中,也都需要A2A3,如果我们能够自底向上开始计算Ai..Aj,并把结果记录下来,后面用到的时候直接查询就可获得,就可以降低时间复杂度了
于是,有了以下自底向上的解法
1 Matrix_Chain_Order(p, 1, n)
2 {
3 for(t=1;t<n+1;i++)
4 f[t][t]=0;
5 for(m=2;m<n;m++)
6 {
7 for(i=1;i<=n-m+1;i++)
8 {
9 j=i+m-1;
10 f[i][j]=max_int;
11 for(k=i;k<j;k++)
12 {
13 q = f[i][k]+f[k+1][j]+p[i-1]*p[k]*p[j];
14 if(q<f[i][j])
15 {
16 f[i][j]=q;
17 s[i][j]=k;
18 }
19 }
20 }
21 }
22 return f and s;
23 }
三层循环,每一层中的循环变量值至多为n-1,故时间复杂度为O(n3),时间复杂度有指数级 降低到了多项式时间,而付出的代价是增加了O(n2)的辅助空间
动态规划的思想就是以空间为代价,降低算法的时间复杂度