動態規劃經典問題 矩陣鏈乘

2021-06-03 21:37:22 字數 2763 閱讀 3236

問題描述:給定n個矩陣,其中ai與ai+1是可乘的,i=1,2,3...n-1.考慮這n個矩陣的乘積。由於矩陣乘法滿足結合律,故計算矩陣的連乘積可以有許多不同的計算機次序。這種計算次序可以用加括號的方式確定。若乙個矩陣鏈乘的計算次序完全確定,這時就說該鏈乘已完全加括號。完全加括號的矩陣鏈乘可遞迴的定義如下:

1,單個矩陣是完全加括號的。

2,矩陣鏈乘的乘積a是完全加括號的,則a可表示為2個完全加括號的矩陣鏈乘的乘積b和c的乘積並加括號。既:a=(bc)

例如:矩陣鏈乘a1a2a3a4可以有以下幾種完全加括號的方式:((a1a2)(a3a4))     (a1(a2(a3a4)))  (a1((a2a3)a4))  ((a1(a2a3))a4) (((a1a2)a3)a4),每一種加括號的方式確定了乙個計算的次序,不同的計算機次序與矩陣鏈乘的計算量有密切關係。

為了說明這個問題,回憶一下兩個矩陣相乘的相關概念。矩陣a和矩陣b可乘的條件是矩陣a的列數等於矩陣b的行數,若a是乙個pxq的矩陣, b是乙個qxr的矩陣,則其乘積c=ab是乙個pxr的矩陣,且標準的兩個矩陣相乘所需要的計算量為pqr次乘法操作。

考慮三個矩陣鏈乘的例子,設這三個矩陣的維數分別為10x100,100x5, 5x50若按第一種加括號方式((a1a2)a3)計算,則所需要的乘法次數為10x100x5+10x5x50=7500,若按第二種加括號方式(a1(a2a3))計算,則所需要的乘法次數為100x5x50+10x100x50=75000.第二種加括號方式是第一種的10倍。由此可以看出,不同的加括號方式所確定的不同的計算次序對矩陣鏈乘的運算量影響是巨大的。

問題定義:給定n個矩陣,矩陣ai的維數為pi-1xpi,i=1,2,...n. 如何給矩陣鏈乘a1xa2xa3x...xan完全加上括號,使得矩陣鏈乘中乘法次數最少。

我們首先想到了窮舉法,列舉所有加括號方法,然後選出計算量最少的那種方法。但這種方法耗費時間多不說,我到現在也沒想出怎麼列舉所有加括號方法,總不能挨個指定吧,當矩陣鏈短的時候可以,當很長的時候腫麼辦???不得不承認,我自己腦子太笨了,根本就不是搞演算法的料。。呵呵

我們還是用老方法,要用動態規劃方法,先看本題有沒有最優子結構特徵。上邊有兩句話很鍵,尤其是第二句:1,單個矩陣是完全加括號的。

2,矩陣鏈乘的乘積a是完全加括號的,則a可表示為2個完全加括號的矩陣鏈乘的乘積b和c的乘積並加括號。既:a=(bc)。。什麼意思呢?也就是說,如果乙個矩陣鏈已經完全加括號了,那麼它可以表示為兩個已經完全加括號了的矩陣鏈的乘積加括號,比如((a1a2)(a3a4))可以表示為已經加完括號的(a1a2)和(a3a4)的乘積加括號。((a1(a2a3))a4)可表示為a4和(a1(a2a3))乘積加括號。而(a1(a2a3))又可表示成a1和(a2a3)乘積加括號形式,這是乙個遞迴的形式。這就構成了原問題的乙個子問題。

我們可以這樣描述:矩陣鏈乘a1xa2xa3x...xan已經完全加上括號,則它必然在某乙個矩陣ai上分開為兩個矩陣。具體在哪個ai上,在哪處分開,應該在讓這個矩陣鏈分開之後再加括號的代價最少的那乙個位置上,那在哪乙個上最少呢,我們不知道,需要從頭遍歷,並記錄當前最少的計算量的那個矩陣ai,所以這個問題的出發點是在哪乙個矩陣中分開

狀態轉移方程怎麼寫呢?假設是在k處分開,那麼這個時候的代價就是c[1,n]=c[1,k]+c[k+1,n]+p0*pk*pn,就是前乙個矩陣鏈的最少計算量+後乙個矩陣最少計算量+這兩個相乘的最少計算量。

既然用動態規劃,那就應該遍歷所有狀態空間,即所有的子問題。而這裡的子問題就是任一兩對矩陣之間加括號的最少代價,所以我們應該設立乙個資料結構來表示和儲存這子問題的答案。那該用什麼資料結構來表示呢。我們可以用c[i][j]來表示矩陣i和矩陣j之間加括號的代價。所以我們定義乙個二維陣列c[n][n],來表示和儲存,而c[1][n]就是我們要求的最終狀態。

資料結構儲存好了,演算法怎麼設計呢。

我剛開始有乙個錯誤的思路,就和前邊的揹包和lcs一樣,從頭開始依次遍歷,也就是從1--n這個順序。這樣是思維慣性造成的,是錯誤的,因為假設當我們遍歷到c[1][3]時,而我們在找分開點k的時候需要用到c[1,1]+c[2,3]+p0*p1*p3,而這個時候c[2,3]根本就還沒開始算。

我們發現這樣乙個規律:當我們在計算某一串個數為n矩陣鏈加括號的最少代價時,需要知道所有這些n-1個,n-2個,n-3個...1個等這些矩陣鏈的代價,就像剛才的c[1][3]例子,我們在計算它時需要知道所有2個矩陣相乘和1個矩陣相乘時的代價,即需要知道,a1,a2,a3,(a1a2),(a2a3)的代價,當然,這裡的a2用不上。。。

說到這裡,我們知道了我們遍歷的順序是要按照矩陣鏈的個數從2個開始到n個結束,1個矩陣相乘的代價不用計算是0,而n個矩陣相乘的代價就是我們要求的最終結果。

核心**如下

int c[n][n];

int flag[n][n];

for(i=1;i<=n;++i)

for(int l=2;l<=n;++l)

{ for(int i=1;i<=n-l+1;++i)

{ min=0xffffff;//初始為乙個無窮大的數

int j=i+l-1;

for(int k=i;k最少代價求完之後,該如何構造出這個最優解來呢。這個對於我來說比較難於理解,看了書上寫的,雖說看明白一些,但仍然有一些模糊。

要對矩陣鏈進行加括號,其實本質就是找出矩陣鏈在**斷開,所以我們設了乙個陣列flag[i][j]來儲存矩陣鏈ai....aj之間的分開點k。

我們可以利用flag陣列儲存的資訊設計乙個遞迴結構。

output(a,flag,i,j)

{ if(i==j)//遞迴出口,只有兩個以上的矩陣相乘才需要加括號,乙個矩陣不需要加括號

{ cout<<"a"<

這個問題的動態規劃問題的實質是決定矩陣鏈從哪乙個地方斷開。

矩陣鏈乘 動態規劃

普通矩陣相乘 define row a 2 define col a 2 define col b 3 void matrix mul int mata row a col a int matb 2 col b int c row a col b 兩個相容矩陣相乘,相容是指矩陣a的行必須等於矩陣b的...

動態規劃 矩陣鏈乘問題分析

一.問題簡述 給定n個矩陣,其中a i 和a i 1 是可乘的,這n個矩陣的連乘積a 1 a 2 a n 由於矩陣的乘法滿足結合律,故計算矩陣的連乘積有許多不同的計算次序,而不同的計算次序,所需要計算的連乘次數也是不同的,求解連乘次數最少的矩陣連乘最優次序。輸入乙個序列p 矩陣a的維數為pi 1 p...

C 動態規劃 矩陣鏈乘

c 動態規劃 矩陣鏈乘 1 問題描述 給定n個矩陣構成的乙個鏈給定 a1,a2,an 其中i 1,2,n.矩陣ai的維數為pi 1 pi,如何確定計算矩陣連乘積的計算次序,使得依此次序計算矩陣連乘積需要的數乘次數最少。2 最優子結構 對乘積a1a2.an的任意加括號方法都會將序列在某個地方分成兩部分...