矩陣鏈乘法問題 (演算法)

2021-08-30 04:37:09 字數 2307 閱讀 5743

一、概述

以兩個矩陣相乘為例,a1*a2,a1和a2為兩個矩陣,假設a1的行列數是p*q,a2的行列數是q*r。注意這裡由於是a1乘以a2,所以a1的列數要等於a2的行數,否則無法做矩陣乘法,滿足上述條件的矩陣,我們稱之為「相容」的。那麼對於a1*a2而言,我們需要分別執行p*r次對應a1的行元素乘以a2的列元素,根據線性代數知識,不難得出我們一共需要執行p*q*r次乘法。

對於兩個矩陣相乘,一旦矩陣的大小確定下來了,那麼所需執行的乘法次數就確定下來了。那麼對於兩個以上的矩陣呢?是不是也是這樣呢。實際上,對於多個矩陣相乘,乘法執行的次數與「劃分」有關。例如:

以矩陣鏈為例,假設三個矩陣的規模分別為10x100,100x5和5x50。

①以((a1*a2)*a3)方式劃分,乘法執行次數為:10*100*5+10*5*50=5000+2500=7500次

②以(a1*(a2*a3))方式劃分,乘法執行次數為:100*5*50+10*100*50=25000+50000=75000次

我們可以發現,對於同樣的矩陣鏈相乘而言,不同的劃分,乘法次數居然相差10倍。

二、如何獲得最佳的矩陣鏈乘法劃分和最少次數

其實這裡與「鋼管切割」有相似之處,在鋼管切割問題中,我們使用乙個一維陣列來儲存最佳收入,另乙個一維陣列來儲存切割的劃分處。

而這裡,我們也可以將矩陣鏈看成一根要分割的「鋼管」,只是這裡記錄的兩個陣列需要是二維的,因為我們需要記錄的不僅是從**「斷開」,還需要記錄"每一段"到**截止。如下圖:

使用乙個長度為n+1的一維陣列p來記錄每個矩陣的規模,其中n為矩陣下標i的範圍1~n,例如對於矩陣ai而言,它的規模應該是p[i-1]到p[i]。由於i是從1到n取值,所以陣列p的下標是從0到n。

用於儲存最少乘法執行次數和最佳分段方式的結構是兩個二維陣列m和s,都是從1~n取值。m[i][j]記錄矩陣鏈的最少乘法執行次數,而s[i][j]則記錄 最優質m[i][j]的分割點k。

需要注意的一點是當i=j時,m[i][j]=m[i][i]=0,因為乙個矩陣不需要任何乘法。

假設矩陣鏈從ai到aj,有j-i+1個矩陣,我們從k處分開,將矩陣鏈分為ai~ak和ak+1到aj兩塊,那麼我們可以比較容易的給出m[i][j]從k處分隔的公式:

m[i][j]=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];

在一組確定的i和j值的情況下,要使m[i][j]的值最小,我們只要在所有的k取值中,i<=k

假設l為矩陣鏈的長度,那麼l=j-i+1。當l=1時,只有乙個矩陣,不需要計算。那麼我們可以從l=2到n進行迴圈,對每個合理的i和j值的組合,遍歷所有k值對應的m[i][j]值,將最小的乙個記錄下來,儲存到m[i][j]中,並將對應的k儲存到s[i][j]中,就得到了我們想要的結果。

根據上面的分析,不難給出過程的**,注意這裡也是使用的自底向上的方法,參看「鋼管切割」

//ai矩陣的行列分別是p[i-1]和p[i],1<=i<=n /*

* 求解最少次數的乘法括號劃分方案

*/void matrix_chain(int* p, int n, int** m, int** s)

int l = 0; //l為矩陣鏈的長度

//m[i][j]的第乙個引數

int i = 0;

//m[i][j]的第二個引數

int j = 0;

int tmp = 0;

//②以長度l為劃分,l從2開始到n

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

}} }

}

上面的**,我們就求得了每種i和j組合對應的最小乘法次數和對應的最佳分割處s[i][j]。

經過執行上面的**,我們就準備好了s[i][j],其中包含最佳分割資訊。我們可以使用一種類似於中序遍歷的方法來輸出劃分方式,比如對和他們對應的下標陣列p而言。

void print_optimal_parens(int** s, int i, int j)  else 

}

比如對於陣列p=和經過上面兩段**的呼叫,輸出劃分結果:

((a1a2)((a3a4)a5))

最少乘法次數為:330次

備註:動態規劃是一種將問題例項分解為更小的、相似的子問題,並儲存子問題的解而避免計算重複的子問題,以解決最優化問題的演算法策略。

備忘錄法是動態規劃方法的變形。與動態規劃演算法不同的是,備忘錄方法的遞迴方式是自頂向下的,而動態規劃演算法則是自底向上的。

矩陣鏈乘法問題

問題描述 詳見演算法導論p197 p198 已知 給定n個矩陣構成的乙個矩陣鏈 a1,a2,an 矩陣ai的維數為pi 1 pi 求 決定該矩陣鏈的乘法結合順序 即加括號 使得矩陣鏈乘法的執行時間最短 幾個前提概念 首先判斷是否具有最優子結構假設ai.aj的矩陣鏈乘法的最優解是在ak與ak 1之間分...

演算法導論 矩陣鏈乘法

問題描述 給定有n個連乘矩陣的維數,要求計算其採用最優計算次序時所用的乘法次數,即所要求計算的乘法次數最少。例如,給定三個連乘矩陣的維數分別是10 100,100 5和5 50,採用 a1a2 a3,乘法次數為10 100 5 10 5 50 7500次,而採用a1 a2a3 乘法次數為100 5 ...

Python演算法 矩陣鏈乘法

題目解析參考 動態規劃 矩陣鏈乘法 矩陣乘法是乙個滿足結合律的運算。顯然,對於矩陣a b c來說,ab c 與 a bc 是等價的,我們可以根據自己的心情選擇任意的運算順序,總之,結果都是一樣的。糟糕的是,對計算機來說可不是這麼回事,若我們假定矩陣 a 10,20 b 20,30 c 30,40 那...