动态规划算法——矩阵链相乘
一、递归实现
伪代码描述:
RecurMatrixChain(P,i,j)
输入:矩阵链Ai..j的输入为向量P=<Pi-1,Pi,···,Pj>,其中1≤i≤j≤n
输出:计算Ai..j的所需最小乘法运算次数m[i,j]和最后一次运算的位置s[i][j]
1 if i=j 2 then m[i,j]←0; s[i,j]←i; return m[i,j] 3 m[i,j]←∞ 4 s[i,j]←i 5 for k←i to j-1 do //考虑所有可能的划分位置 6 q←RecurMatrixChain(P,i,k)+RecurMatrixChain(P,k+1,j)+Pi-1PkPj 7 if q<m[i,j] 8 then m[i,j]←q //用找到的更好优化函数值替换原值,并记录划分位置 9 s[i,j]←k 10 return m[i,j]
指数级别复杂度:T(n) ≥ 2n-1
Python代码实现:
import sys P = [30,35,15,25,10,20] m = [[0]*6 for i in range(6)] s = [[0]*6 for i in range(6)] def recurMatrixChain(P,i,j): if i==j: m[i][j]=0 s[i][j]=i return m[i][j] m[i][j]=sys.maxint #无穷大 s[i][j]=i for k in range(i,j): q=recurMatrixChain(P,i,k)+recurMatrixChain(P,k+1,j)+P[i-1]*P[k]*P[j] if q<m[i][j]: m[i][j]=q s[i][j]=k return m[i][j] mm = recurMatrixChain(P,1,5) print mm
二、迭代实现
伪代码描述:
MatrixChain(P,n)
输入:矩阵链A1..n的输入为向量P=<P0,P1,...,Pn>
输出:计算Ai..j的所需最小乘法运算此时m[i,j]和最后一次运算的位置s[i,j],1≤i≤j≤n
1 令所有的m[i,j]初值为0,s[i,j]初值为i,1≤i≤j≤n 2 for r←2 to n do //r为当前计算的链长(子问题规模) 3 for i←1 to n-r+1 do //n-r+1为最后一个r链的前边界 4 j←i+r-1 //计算前边界为i,长为r链的后边界j 5 m[i,j]←m[i+1,j]+Pi-1*Pi*Pj //划分为Ai(Ai+1···Aj),*为普通乘法 6 s[i][j]←i //记录分割位置 7 for k←i+1 to j-1 do 8 t←m[i,k]+m[k+1,j]+Pi-1*Pk*Pj //划分位置是(Ai···Ak)(Ak+1···Aj) 9 if t<m[i,j] //用更好的值替换 10 then m[i,j]←t 11 s[i,j]←k
指数级别复杂度:W(n) = O(n3)
Python代码实现:
P = [30,35,15,25,10,20] M = [[0]*6 for i in range(6)] S = [[0]*6 for i in range(6)] n = 6 for r in range(2,n): for i in range(1,n-r+1): j=r+i-1 M[i][j]=M[i+1][j]+P[i-1]*P[i]*P[j] S[i][j]=i for k in range(i+1,j): 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 print M[i][j] print S[i][j]
Efficiency is intelligent laziness.