動態規劃之矩陣鏈乘法

2021-06-29 14:41:38 字數 3319 閱讀 5509

雖然我們在《動態規劃之鋼條切割》:裡面已經介紹過動態規劃的相關知識,這裡還是提一下動態的兩大特徵:

1.最優子結構,原問題的解是在子問題的最優解的基礎上建立起來的

2.重疊子問題,即在不斷求解子問題的過程中會產生相同的子問題,而不是一直產生新的子問題

現在我們來看乙個例子,假設有三個矩陣:

a1<10,100> a2<100,5> a3<5,50>

令b=a1a2a3,那麼求得矩陣b共需要花費多少代價呢?

先看一下這種情況:

a1乘a2的代價為10*100*5=5000,然後得到乙個a4<10,5>的矩陣

a4再乘上a3的代價為10*5*50=2500

總共花費代價為5000+2500=7500

我們知道矩陣相乘是不滿足乘法交換律,而是滿足乘法結合律的,即我們不可以改變矩陣鏈中各個矩陣的位置,但是我們可以改變矩陣在矩陣鏈中相乘的先後順序

那麼就有這種情況:

先a2乘a3,代價為1000*5*50=25000,得到矩陣a4<100,50>

a1再乘上a4,代價為10*100*50=50000

總共花費代價為25000+50000=75000

比較上面兩種情況,我們知道,通過矩陣的結合律改變矩陣相乘的先後順序,矩陣相乘的總代價是由區別的。

問題:現在給定乙個含有n個矩陣的矩陣鏈(矩陣鏈輸入合法),通過結合律改變矩陣相乘的順序(通過加括號方法),使得矩陣鏈花費的代價最小。

看到這道題,我們首先想到的是用蠻力法來列舉所有的情況,然後找到最小的花費,但是這樣做真的可行嗎?

我們假設p(n)為n個矩陣鏈括號化方案的數量:

通過計算,我們知道,通過蠻力法來求解這個問題,那麼括號化方案的數量將是與n呈指數增長的關係的。

那我們通過運用動態規劃的策略來解決這個問題:

1.刻畫乙個最優解的結構特徵。

2.遞迴的定義最優解的值

3.計算最優解時,一般採用自下而上的方法來求解

4.利用計算出的資訊構造出乙個最優解

步驟一:最優括號化方案的結構特徵

動態規劃的第一步是尋找最優子結構,通過子問題的最優解來構造原問題的最優解。為方便起見,我們用a表示矩陣鏈,為了將矩陣鏈括號化,我們需要在位置k(k>=i && k < j)處將矩陣鏈分開為a和a。也就是說我們首先計算a和a的子矩陣的代價,然後再加上a,a兩者相乘的代價。

步驟二:乙個遞迴解決方案

我們假設:

m[i...j]為矩陣鏈a的標量乘法次數的最小值,那麼矩陣鏈a<1...j>的標量乘法次數為m[1...j]

ri為矩陣ai的行數,ci為矩陣ai的列數,那麼a1<50,500> r1 = 50,c1=500

於是:當a=ai,即矩陣鏈裡矩陣數量為1時,m[i...j]=0

當j>i時,首先計算兩個子問題的最小乘法次數,分別是m[i...k]和m[k+1...j],然後加上a乘上a的乘法次數ri*ck*cj,有

m[i...j]=m[i...k]+m[k+1...j]+ri*ck*cj

上面的公式中k是已知的,但是在實際中我們是不知道的,於是k有[i...j)種選擇,那麼遞迴方程式有:

m[i,j]儲存的是最小的相乘次數,我們用s[i,j]來儲存在a裡面的括號的分割點

步驟三:計算最優代價

我們知道在矩陣a<1..n>中,矩陣的子問題數量為:

這裡首先採用自上而下帶備份的迭代方法實現:

#include #include #include #include using namespace std;

#define maxtrix_chain_length 3

unsigned int mulcost[maxtrix_chain_length][maxtrix_chain_length];

unsigned int dealmincost(std::vector> & matrixchain ,\

unsigned left ,\

unsigned right);

/** * 求解最小花費

* @param matrixchain 矩陣鏈

* @return 最小花費

*/unsigned int getmincost(std::vector> & matrixchain)

unsigned int dealmincost(std::vector> & matrixchain ,\

unsigned left ,\

unsigned right)

mulcost[left][right] = min;

return min;

}int main(int argc, char const *argv)

unsigned int dealmincost(std::vector> & matrixchain ,\

unsigned left ,\

unsigned right)

unsigned int min = uint_max;

for (int k = i; k < j; ++k)

mulcost[i][j] = min;}}

}int main(int argc, char const *argv)

unsigned int dealmincost(std::vector> & matrixchain ,\

unsigned left ,\

unsigned right)

unsigned int min = uint_max;

unsigned int pos;

for (int k = i; k < j; ++k)

}mulcost[i][j] = min;

solution[i][j] = pos;}}

}void printsolution(int left , int right)

{ if(left+2 > right)

return;

cout< matrixchain;

matrixchain.push_back(pair(30,35));

matrixchain.push_back(pair(35,15));

matrixchain.push_back(pair(15,5));

matrixchain.push_back(pair(5,10));

matrixchain.push_back(pair(10,20));

matrixchain.push_back(pair(20,25));

cout<

動態規劃之矩陣鏈乘法

給定乙個n個矩陣的序列,我們希望計算它的乘積 a1a2a3.an,我們可以用括號標定計算次序,然後再利用標準的矩陣乘法演算法來計算,由於矩陣乘法滿足結合律,所以任何一種計算順序最後的計算結果都是相同的。完全括號化的矩陣乘積鏈 它是單一矩陣,或者兩個完全括號化的矩陣乘積鏈的積,並且已經外加括號 例如矩...

動態規劃 矩陣鏈乘法

矩陣鏈乘法問題 給定n個矩陣的鏈,矩陣ai的規模為p i 1 p i 求完全括號化方案,使得計算乘積a1a2 an所需標量乘法次數最少。m i j 表示矩陣鏈ai j所需標量乘法次數的最小值。m i j 0 i j m i j m i k m k 1 j p i 1 p k p j i k s 1....

動態規劃 矩陣鏈乘法

兩個矩陣相乘的計算量,對於一般的矩陣乘法來說,如矩陣a m,n 與矩陣b n,p 相乘需要進行的加法次數為m n p次乘法 由於矩陣乘法滿足結合律,因此矩陣相乘的結合性,會影響整個計算表示式的乘法執行次數 如下面的例子,a b c三個矩陣相乘,其中a 10,5 b 5,20 c 20,3 1 ab ...