1. 程式人生 > >[動態規劃] 矩陣鏈乘法問題

[動態規劃] 矩陣鏈乘法問題

計算順序 get 分享 最優 inf cat 列數 log tps

什麽是矩陣鏈乘法(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; }

[動態規劃] 矩陣鏈乘法問題