什麼是矩陣鏈乘法(Matrix Chain Multiplication)
矩陣鏈乘法問題是指給定一串矩陣序列M₁M2..Mn,求至少需要進行多少次乘法運算才能求得結果
比如對於這個M₁M₂M₃的矩陣鏈, 我們可以先計算M₁M₂然後結果乘以M₃,也可以M₂M₃先算,然後乘以M₁,爲了表達方便,可以用括號表示計算順序。 矩陣鏈M₁M₂M₃有兩種計算順序:((M₁M₂)M₃)和(M₁(M₂M₃))。 那麼不同計算順序有什麼區別? 對於((M₁M₂)M₃): 對於(M₁(M₂M₃)):
我們要做的就是找到讓乘法運算最少的計算順序,換言之就是找一種加括號方式,使得最後乘法運算最少
狀態轉移方程
現用 optimal(M₁M₂) 表示M₁M₂最優計算成本 cost(M₁M₂) 表示M₁M₂計算成本optimal(M₁M₂)=optimal(M₁)+optimal(M₂)+cost(M₁M₂)
optimal(M₁)和optimal(M₂)均爲零;同理
optimal(M₂M₃)=optimal(M₂)+optimal(M₃)+cost(M₂M₃)
(M₁M₂M₃)有兩種加括號方式, 它的最優計算成本是這兩種加括號方式中最優的那個,即:optimal(M₁M₂M₃)=min{optimal((M₁M₂)M₃),optimal(M₁(M₂M₃))}
顯然,這裏說的正是動態規劃思想:我們從局部最優解出發,逐漸構造出大問題(同時局部最優解還有重疊,可以保存計算結果免去後面計算)。狀態方程已經構造出來了,下面就是實際的實現
實現
#include <iostream>
#include <algorithm>
#include <climits>
int dp[1024][1024] = { 0 };
struct Matrix {
int row;
int column;
};
int matrixChainCost(Matrix *ms, int n) {
for (int scale = 2; scale <= n; scale++) {
for (int i = 0; i <= n - scale; i++) {
int j = i + scale - 1;
dp[i][j] = INT_MAX;
for (int k = i; k < j; k++) {
dp[i][j] = std::min(dp[i][j], dp[i][k] + dp[k+1][j] + (ms[i].row*ms[k].column*ms[j].column));
}
}
}
return dp[0][n - 1];
}
int main() {
int n;
std::cin >> n; //n個矩陣組成的矩陣鏈
Matrix *ms = new Matrix[n];
for (int i = 0; i<n; i++) {
std::cin >> ms[i].row; //第i個矩陣的行數
std::cin >> ms[i].column; //第i個矩陣的列數
}
std::cout << matrixChainCost(ms, n);
system("pause");
return 0;
}