动态规划之矩阵链相乘
问题描述
给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2 ,…,n-1。
确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。
思路:
构造递归解
设m[i,j]为矩阵链Ai…Aj的最优解的代价,则
┌ 0 如果i = j
m[i,j] = │
└ min(i≤k<j) {m[i,k] + m[k+1,j] + Ai.row*Ak.col*Aj.col} 如果i < j
假如n=6 则m矩阵为:
(上三角)
首先在对角线0中,每个链仅由一个矩阵的组成,没有数量乘法,因此这个对角线填0。
接着,对角线1由两个连续的矩阵相乘的耗费来填充。如C[2][3]用M2M3M2M3的乘法耗费来填。
余下的对角线根据上面的递推式和先前存储在表中值来填。举例来说,C[2][5]的值为以下三个耗费的最小值:
- (1)计算M2,2M2,2的耗费(即C[2][2])加上计算M3,5M3,5(即C[3][5])的耗费,再加上M2,2M2,2乘以M3,5M3,5的耗费。
- (2)计算M2,3M2,3的耗费(即C[2][3])加上计算M4,5M4,5(即C[4][5])的耗费,再加上M2,3M2,3乘以M4,5M4,5的耗费。
- (3)计算M2,4M2,4的耗费(即C[2][4])加上计算M5,5M5,5(即C[5][5])的耗费,再加上M2,4M2,4乘以M5,5M5,5的耗费。
# 辅助表 m 保存代价 m[i,j]
# 辅助表 s 记录最优值 m[i,j]对应的分割点 k
def maxChain(p):
n = len(p)
m = [[0 for i in range(n)] for j in range(n)]
s = [[0 for i in range(n)] for j in range(n)]
for l in range(2,n): # 对角线
for i in range(1,n-l+1): # 行
j = i+l-1
# m[i][j] = 9999999999
for k in range(i,j):
if(k == i):
m[i][j] = m[i][k] + m[k+1][j] + p[i-1] * p[k] * p[j]
s[i][j] = k
q = m[i][k] + m[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, s
# 输出矩阵链的最优括号化方法
def printOpt(s, i, j):
if i == j:
print("A", i, end='')
else:
# print("(", end="")
print("(", end='')
printOpt(s, i, s[i][j])
printOpt(s, s[i][j]+1, j)
print(")", end='')
print("start=========")
# p = [30, 35, 15, 5, 10, 20, 25]
p = [3, 5, 6, 7, 4]
m, s = maxChain(p)
# print(m)
# print(s)
print("最优括号化方案为:")
printOpt(s, 1, 4)
print("")
print("其标量乘法次数为:", m[1][4])
print("Over=========")