演算法之動態規劃-矩陣鏈相乘(matrix-chain multiplication)
Matrix-chain multiplication
給定一串矩陣
使用動態規劃求解
first step: Characterize the structure of an optimal solution
數學定義:
存在k 使得
把
假設此時的k正好為最優劃分,使得
反證: 如果此時k對原來矩陣序列的劃分不是最優的,則肯定存在另一個k,使得劃分為最優:與假設矛盾。
second step: Recursively define the value of an optimal solution
現在我們定義遞迴求解這個子問題:
數學定義:
定義陣列P,使得矩陣
如圖1:
當
i :Ai⋅⋅j=Ai ,單個矩陣,所以M[i,j]=0 當
i<j :Ai⋅⋅j 可分為Ai⋅⋅k 的矩陣乘規模數加上Ak+1⋅⋅Aj 的矩陣乘規模數,再加上兩個分矩陣的相乘規模數
數學表示式為:M[i,j]=M[i,k]+M[k+1,j]+pi−1pkpj
重點理解pi−1pkpj 表達的意思:現在M[i,k] 可理解為最終行下標為i,列下表為k的矩陣;M[k+1,j] 可理解為最終行下標為k+1,列下表為j的矩陣;再把這兩個矩陣相乘,也就是等同於兩個矩陣相乘的規模數,再結合圖一,得出結果——pi−1pkpj
third step: Compute the value of an optimal solution
- 遞迴演算法:
matrix(p,i,j) {
if i == j
m[i,j] = 0
retrun m[i,j]
m[i,j] = 999999999999
for k = i to j - 1
temp = matrix(p,i,k) + matrix(p,k+1,j) + p[i-1]p[k]p[j]
if temp < m[i,j]
m[i,j] = temp
return m[i,j]
}
下面看一個例子:對4個矩陣鏈的劃分
圖2:
- 動態規劃:自頂向下
基本思路為:用陣列儲存下計算了的值,這樣就避免了大量的重複計算。這也是動態規劃的精髓所在,以空間換時間。
s[m,n]代表Am··n最優劃分位置為s[m,n],記錄下最優劃分的位置
memory-matrix(p) {
n = p.length - 1
let s[n,n] be a global array
let m[n,n] be a new array
for i = 1 to n
for j = i to n
m[i,j] = 999999999
return look-chain(m,p,1,n)
}
look-chain(m,p,i,j) {
if m[i,j] < 9999999999
return m[i,j]
if i == j
m[i,j] = 0
else for k = i to j - 1
q = look-chain(m,p,j,k) + matrix(m,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]
}
At last:Construct an optimal solution from computed information
遞迴輸出
printPartition(s,i,j) {
if i == j
print "Ai"
else print "("
printPartition(s,i,s[i,j])
printPartition(s,s[i,j]+1,j)
print")"
}