講解: 個矩陣相乘時, 爲 行 列的矩陣,以 爲例進行分析,這些矩陣的乘積有多種計算順序。舉個例子,我們按習慣的從左到右的順序進行計算時可以寫作 ,從左到右計算時可以寫作 。除此之外還有 等等,計算的順序多種多樣。這些計算順序得出的結果(矩陣鏈乘積)完全相同,但不同順序下的 “ 乘法運算次數 ” 會有所差異。
處理矩陣鏈乘法問題時,如果檢查所有可能的計算順序,那麼算法的複雜度將達到 。不過,由於這個問題能夠分割成更小的局部問題,我們可以運用動態規劃法。
首先, 只有一種計算方法(順序),需要 次乘法運算。同理, 也只有一種計算方法,需要 次乘法運算。歸納後可知, 只有一種計算方法,需要 次乘法運算。於是我們將這些運算次數視爲 “ 成本 ” 記錄在表中。
接下來求 的最優計算方法。舉個例子,計算 的最優計算方法時,我們要分別算出 與 的成本,取其中最小的一個作爲 的成本記錄在表中。這裏:
- 的成本 的成本 的成本
- 的成本 的成本 的成本
請注意,這一步用到的 和 的成本可以直接從表中引用,不需要再進行計算。另外還要注意,當 時, 的成本爲 。
一般情況下,矩陣鏈乘法 的最優解就是 的最小成本(其中 )。
舉個例子, 時的最優解就是下列式子中的最小值。
- 的成本 的成本 的成本
- 的成本 的成本 的成本
- 的成本 的成本 的成本
- 的成本 的成本 的成本
現在來看看這個算法的具體實現方法。先準備下述變量。
該二維數組中, 表示計算 時所需要乘法運算的最小次數 | |
該一位數組用於儲存矩陣的行列數,其中 是 的矩陣 |
利用上述變量,我們可以利用下面的式子求出 。
這個算法的實現方法如下:
matrixChainMultiplication()
for i = 1 to n
m[i][j] = 0
for l = 2 to n
for i = 1 to n - l + 1
j = i + l - 1
m[i][j] = INFTY
for k = i to j - 1
m[i][j] = min(m[i][j], m[i][k] + m[k + l][j] + p[i - l] * p[k] * p[j])
考察:這個算法需要讓對象的矩陣對象的數量 從 逐步增加到 ,同時對於每個 要通過不斷改變 和 來改變指定範圍。除此之外,還需要在 和 的範圍內讓 不斷變化。整個算法由三重循環構成,因此複雜度爲 。
#include <iostream>
#include <algorithm>
using namespace std;
static const int N = 100;
int main() {
int n, p[N + 1], m[N + 1][N + 1];
cin >> n;
for (int i = 1; i <= n; i++)
cin >> p[i - 1] >> p[i];
for (int i = 1; i <= n; i++) m[i][j] = 0;
for (int l = 2; l <= n; l++) {
for (int i = 1; i <= n - l + 1; i++) {
int j = i + l - 1;
m[i][j] = (1 << 21);
for (int k = i; k <= j - 1; k++)
m[i][j] = min(m[i][j], m[i][k] + m[k + l][j] + p[i - l] * p[k] * p[j]);
}
}
cout << m[l][n] << endl;
return 0;
}