一、問題描述
給定n個數字矩陣a1,a2,…,an,其中ai與ai+1是可乘的,設ai是pi-1*pi矩陣, i=1,2,…,n。求矩陣連乘a1a2...an的加括號方法,使得所用的乘次數最少。
例子三個矩陣連乘,可以有(a1a2)a3和a1(a2a3)兩種方法求積 ,乘法次數分別為: p0p1p2+p0p2p3和p0p1p3+p1p2p3
假設p0=10, p1=100, p2=5, p3=50, 兩種方法的次數分別是:7500 和 75000
明顯可以看出,兩種乘法在效率上是有較大差異的,計算機實現乘法比實現加法要複雜,所以如何使乘法次數最小是乙個值得**的問題
如果使用蠻力演算法,對所有可能的加括號方法遞迴搜尋,則:
時間複雜度為指數級別,那麼就需要有更優的方法來計算最佳的矩陣連乘方法
二、最優子結構性質
維基百科:如果問題的最優解所包含的子問題的解也是最優的,我們就稱該問題具有最優子結構性質(即滿足最優化原理)
通常來說,乙個問題可以使用動態規劃求解,必須具有最優子結構性質。所以,如果我們證明該問題具有最優子結構性質,我們就可以使用動態規劃的方法來得到它的最優解,通常可以使用反證法進行證明。
證明:設(a1…ak)(ak+1…an) 具有最少乘法次數,則(a1…ak)中加括號的方法使a1..ak乘法次數最少。否則設存在另一種加括號方法(a1…ak)'更優,則(a1…ak)'(ak+1…an) 比 (a1…ak)(ak+1…an) 更優,矛盾。同理, (ak+1…an) 內的連乘方法也是最優的。
三、實現
用m[i][j]表示ai到aj連乘的最小次數,則有遞推關係:
這裡使用一種自底向上的動態填表的方式來進行求解。
由上式及下表可以知道,每當我們要求得乙個m[i][j]的值時,都需要知道它左邊位置和下邊位置所有的值,這樣來理解的話就很容易實現了。
i/j演算法過程示例
6個矩陣連乘:p=[30,35,15,5,10,20,25]
計算過程:
i/j還可以增加乙個矩陣記錄分割點,求得m[i][j]值的那乙個k點即為最佳分割點。
該演算法的時間複雜度為
o(n^3)
**示例
#include
using namespace std;
//矩陣連乘問題的解
int matrixchainorder(int n,int p,int a, int b){
int m[n+1][n+1], s[n+1][n+1];//m記錄乘法操作次數,s記錄分割點k
for(int i = 1;i <= n;i++){
m[i][i] = 0;
s[i][i] = 0;
for(int i = n-1;i >= 1;i--){
for(int j = i+1;j <= n;j++){
m[i][j] = 10000000;
for(int k = i;k <= j-1;k++){
int sum = m[i][k] + m[k+1][j] + p[i-1]*p[k]*p[j];
if(sum < m[i][j]){
m[i][j] = sum;
s[i][j] = k;
printf("%d %d", m[a][b], s[a][b]);
int main(){
int n, i, j;
cin >> n;
int p[n+1];
for(int i = 0;i < n+1;i++)cin >> p[i];//第i個矩陣為pi*p(i+1)
cin >> i >> j;
matrixchainorder(n, p, i, j);
矩陣連乘(動態規劃)
題目描述 給定n個矩陣 a1,a2,an 其中ai與ai 1是可乘的,i 1,2 n 1。如何確定計算矩陣連乘積的計算次序,使得依此次序計算矩陣連乘積需要的數乘次數最少。例如 a1 a2 a3 a4 a5 a6 最後的結果為 a1 a2a3 a4a5 a6 最小的乘次為15125。思路 動態規劃演算...
動態規劃 矩陣連乘
includeusing namespace std 無論括號怎麼分這些連續相乘的矩陣,最後括號都可以歸結到只有兩對括號,把整個連乘的矩陣分成兩部分 0 i j m i j min i 遞迴計算矩陣連乘 int liancheng int i,int j,int p,int s return min...
動態規劃 矩陣連乘
動態規劃常常用來解決,具有最優子結構,重疊子問題的物件。最優子結構 即通過分析問題,將問題分解為多個子問題。然後每個子問題繼續分解為更多子問題。從底往上求出最有值,由最優值確定最優解。重疊子問題 在計算過程中不同子問題可能都會計算某個值。若每個子問題都去求解同乙個值,浪費時間。動態規規劃對每乙個子問...