動態規劃算法的基本要素:
- 最優子結構性質
假設A1*A2*A3*...*An在k處斷開爲最優,那麼只需要保證A1*...*Ak和Ak*..*An兩個子序列的分割也是最優,就能保證該結果是最優。
- 子問題重疊性
問題描述:
對於多個矩陣連乘,不同的分割次序會導致計算次數的不同,所以要找到最優化的分割,減少計算量。
A1 | A2 | A3 | A4 | A5 | A6 |
30*35 | 35*15 | 15*5 | 5*10 | 10*20 | 20*25 |
計算子問題的最優解並保存:
矩陣m保存子問題的最優計算量,矩陣s保存子問題的最優分割方式。
矩陣m:
矩陣s:
舉例說明:
m[0][3]=7875,s[0][3]=1表示對於子問題(分割A1*A2*A3),需要的最少計算量爲7875次,最優分割點在位置1,也就是分割爲A1*(A2*A3)。
#include "stdafx.h"
#include<iostream>
#include<cstdlib>
using namespace std;
void MatrixChain(int *p, int n, int m[][6], int s[][6]);
void TraceBack(int i, int j, int s[][6]);
int main()
{
int n = 6;
int p[7] = { 30,35,15,5,10,20,25 };
int m[6][6] = {};
int s[6][6] = {};
for (int i = 0; i < 6; i++)
for (int j = 0; j < 6; j++)
{
m[i][j] = 0; s[i][j] = 0;
}
MatrixChain(p, n, m, s);
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 6; j++) cout << s[i][j] << "\t";
cout << endl;
}
//cout << s[0][5]<<endl;
TraceBack(0, 5, s);
system("pause");
return 0;
}
//構造最優解矩陣
void MatrixChain(int *p, int n, int m[][6], int s[][6])
{
for (int i = 0; i < n; i++) m[i][i] = 0;//將矩陣分割成單個的矩陣,此時計算量爲0
for (int r = 2; r <= n; r++)//將矩陣分割爲2 - n 個矩陣,計算此時的計算量
for (int i = 0; i < n-r+1; i++)
{
int j = i + r - 1;
//將矩陣連乘m[i][j]最優分割點初始化爲第i個矩陣處
m[i][j] = m[i + 1][j] + p[i] * p[i+1] * p[j+1];
s[i][j] = i+1;
//尋找比初始化分割點更優的分割點
for (int k = i + 1; k <= j; k++)
{
int temp = m[i][k] + m[k + 1][j] + p[i] * p[k+1] * p[j+1];
if (temp < m[i][j]){m[i][j] = temp;s[i][j] = k+1;}
}
}
}
//遞歸搜索最優解
void TraceBack(int i, int j, int s[][6])
{
//查找最優解位置s[i][j]
if (i == j || i == j-1) return;//已經分出來單個矩陣,或者兩個矩陣相乘的部分,不需要再進行分割
else
{
TraceBack(i, s[i][j] - 1, s);//遞歸分割左邊部分
cout << s[i][j] << "\t";//輸出分割點位置
TraceBack(s[i][j], j, s);//遞歸分割右邊部分
}
}
參考資料
- 算法設計與分析--王曉東