問題描述:
利用標準矩陣乘法計算矩陣 M1, M2, M3 之和虐急,假設維數分別為2 * 10, 10 * 2志笼, 2 * 10讯蒲。那么(M1M2)M3 = 2 * 10 * 2 + 2 * 2 * 10 = 80, 而M1(M2M3) = 2 * 10 * 10 + 10 * 2 * 10 = 400, 次數相差5倍痊土。如何快速地求出最少的次數?
矩陣鏈Mi, j-1 = Mi * ··· * Mj-1墨林, Mj, k = Mj * ··· * Mk
Mi, k = Mi, j-1 + Mj, k + rirjrk+1(因為兩個矩陣相乘的次數等于(第一個矩陣的行數 * 列數) * 第二個矩陣的列數)
所以有一個遞推式:
C[i, k] = min{C[i, j-1] + C[j, k] + rirjrk+1} (i <= j <= k)
i 與 k 相乘赁酝, 它們之中有 k - i 種組合方式。
對于n個矩陣旭等,為了減少重復計算酌呆,我們可以用一張n*n的表來記錄 C[i, j] 的值,我們最終要得到得到值是C[1, n]搔耕。事實上隙袁,自底向上地填表可以避免重復計算。
代碼示例:
#include <iostream>
#include <iomanip>
#include <memory.h>
using namespace std;
int N = 21;
int C[21][21];
struct Matrix
{
int col; // 行
int row; // 列
friend istream& operator>>(istream& cin, Matrix& m);
};
Matrix* mat = 0;
istream& operator>>(istream& cin, Matrix& m)
{
cin>>m.row>>m.col;
return cin;
}
int theMin(int i, int j)
{
int tmp = 0;
int ans = 600000;
for(int x = i; x < j; x++) {
tmp = C[i][x] + C[x+1][j] + mat[i-1].row * mat[x-1].col * mat[j-1].col; // 數組從0開始,當然不用0號也可以
if (tmp < ans) {
ans = tmp;
}
}
return ans;
}
void output()
{
int N = 6;
for (int i = 1; i < N; i++) {
for (int j = 1; j < N; j++) {
cout<<setw(6)<<C[i][j]<<" ";
}
cout<<endl;
}
}
int main()
{
// 不進行合法性檢查菩收。請保證輸入合理
int n;
cin>>n;
mat = new Matrix[n];
memset(C, 0, N * N * sizeof(int));
for (int i = 0; i < n; i++) {
cin>>mat[i];
}
// 因為所有長為2的鏈梨睁,都是由長度為1的鏈的結果求出的,所有長為3的鏈娜饵,是由長為2的鏈的結果求出的坡贺,所以從長為1的鏈開始
for (int i = 1; i < n; i++) {
for (int j = 1; j <= n; j++) {
if (j + i > n) {
break;
}
C[j][j+i] = theMin(j, j+i);
}
}
cout<<"theMin: "<<C[1][n];
cout<<endl;
output();
return 0;
}