算法设计与分析——动态规划之矩阵连乘
1、矩陣
首先,要了解什么是矩陣連乘問(wèn)題,當(dāng)然得先了解什么是矩陣了,學(xué)過(guò)線性代數(shù)的同學(xué)應(yīng)該都知道,所以這里就簡(jiǎn)單的介紹一下什么是矩陣:
在數(shù)學(xué)中,矩陣(Matrix)是一個(gè)按照長(zhǎng)方陣列排列的復(fù)數(shù)或?qū)崝?shù)集合。例如:一個(gè)n*m的矩陣A=[a[i,j]]就是像下面一樣的一個(gè)有著n行m列的二維數(shù)組:
2、矩陣連乘
學(xué)過(guò)線性代數(shù)的同學(xué)一定知道,一個(gè)p * q的矩陣A和一個(gè)q * r的矩陣B的乘積是一個(gè)新的p * r的矩陣C,即內(nèi)積相同可乘。
舉個(gè)簡(jiǎn)單例子:
3、矩陣連乘特點(diǎn)
如果存在兩個(gè)矩陣A和B,如果AB能夠計(jì)算乘積,則BA不一定能夠計(jì)算乘積。
即使存在兩個(gè)矩陣A和B,滿足AB能夠相乘,BA也能夠相乘,但最后得出來(lái)的矩陣卻很有可能是不一樣的。
矩陣連乘可以被遞歸成如下形式:
矩陣連乘無(wú)論按照什么樣的乘積順序,最后計(jì)算出來(lái)的矩陣雖然“樣子”不一樣,但是計(jì)算出來(lái)的值卻無(wú)論如何都是一樣的。
4、矩陣連乘的復(fù)雜度分析
假設(shè)有一個(gè)p * q的矩陣A和q * r的矩陣B,則他們的乘積矩陣C=AB按照如下方式計(jì)算:
我們發(fā)現(xiàn),矩陣C的規(guī)模應(yīng)該為【p * r】,則矩陣C應(yīng)該一共有【p * r】個(gè)實(shí)體并且每個(gè)實(shí)體需要【q】次的計(jì)算才能夠算出來(lái)。因此,為了計(jì)算矩陣C的值,我們一共需要執(zhí)行【p * q * r】這么多次計(jì)算。
因此,我們可以近似的認(rèn)為矩陣連乘的復(fù)雜度就是矩陣連乘所需要的總次數(shù),即O(p * q * r)。
5、矩陣連乘的計(jì)算次數(shù)與計(jì)算順序的關(guān)系
假設(shè)有一個(gè)p * q規(guī)模的矩陣A,一個(gè)q * r規(guī)模的矩陣B,并且我們現(xiàn)在再加上一個(gè)規(guī)模為r * s的矩陣C,那么這三個(gè)矩陣的乘積ABC有兩種計(jì)算順序:
(AB)C
A(BC)
那么,肯定有同學(xué)要問(wèn)了,這兩種計(jì)算順序有什么不同嗎?無(wú)論采用哪種計(jì)算順序他們的結(jié)果肯定都是一樣的啊!那我們?yōu)槭裁匆m結(jié)它們的計(jì)算順序呢?不是多此一舉嗎?
那就讓我們來(lái)“探索”一下,這兩種計(jì)算順序有什么不同吧:
對(duì)于第一種計(jì)算順序來(lái)說(shuō),總共需要的計(jì)算次數(shù)為:
因?yàn)锳B共需要計(jì)算【p * q * r】次,并且生成一個(gè)規(guī)模為【p * r】的中間矩陣,這個(gè)中間矩陣再與矩陣C相乘,又需要計(jì)算【p * r * s】次,并且生成一個(gè)規(guī)模為【p * s】的矩陣,這個(gè)矩陣也就是最后的結(jié)果,因此,按照第一種順序計(jì)算,一共需要的計(jì)算次數(shù)如下:
同理,按照第二種計(jì)算順序,我們一共需要計(jì)算下面這么多次:
此時(shí)同學(xué)們注意了!!!好像兩種計(jì)算順序分別所需要的計(jì)算次數(shù)竟然是不一樣的!!!那么,讓我們把真實(shí)數(shù)據(jù)帶入,來(lái)看一看差距有多大吧!
假設(shè)p=5,q=4,r=6并且s=2,則:
大的不同!按照第一種計(jì)算順序,我們需要計(jì)算180次,而按照第二種計(jì)算順序,我們只需要計(jì)算88次就夠了!!!但是這兩種順序計(jì)算出來(lái)的矩陣的值卻始終是一樣的,真是太神奇了,計(jì)算順序竟然能夠影響所需要的計(jì)算次數(shù),因此,對(duì)于矩陣連乘來(lái)說(shuō),計(jì)算順序是非常重要的!
6、矩陣連乘問(wèn)題
問(wèn)題描述:
給你一系列的矩陣A1, A2, A3, ......,An和一系列的整數(shù)P0, P1, P2, ....., Pn,每個(gè)矩陣 Ai 的規(guī)模為Pi-1 * Pi。
現(xiàn)在,請(qǐng)你計(jì)算這些矩陣連乘所需要的最少的計(jì)算次數(shù)是多少?
針對(duì)這道題目,其實(shí)我們可以很清晰的認(rèn)識(shí)到,需要找出最少的計(jì)算次數(shù),就是需要我們找到“正確”的計(jì)算順序!
此時(shí)肯定有同學(xué)會(huì)想到,我們可以使用暴力破解啊!循環(huán)算出所有可能的計(jì)算順序的計(jì)算次數(shù),然后取最小計(jì)算次數(shù)的那一個(gè),就是我們需要的結(jié)果,例如,求A1A2A3A4,我們可以暴力循環(huán)出下面4種計(jì)算順序來(lái):
雖然這種方法確實(shí)也能夠計(jì)算出最少計(jì)算次數(shù),但是,我們知道暴力循環(huán)的復(fù)雜度是非常高的,如果我們需要計(jì)算的矩陣序列不止4個(gè)矩陣,而是很長(zhǎng)的一串矩陣序列,那么將會(huì)非常的耗時(shí),我們有這個(gè)時(shí)間計(jì)算最少計(jì)算次數(shù),還不如隨便找一個(gè)計(jì)算順序直接算得了。暴力搜索的時(shí)間復(fù)雜度為:Ω(4n/n3/2)
難道,我們就只能用暴力算法了嗎?當(dāng)然不是,接下來(lái)就是我們的重頭戲:DP(動(dòng)態(tài)規(guī)劃)了。
7、動(dòng)態(tài)規(guī)劃解決矩陣連乘
1️⃣ 找出最優(yōu)子結(jié)構(gòu),在本問(wèn)題中,即找出如何劃分“括號(hào)”的方法。
首先,讓我們把復(fù)雜的問(wèn)題分解成子問(wèn)題,對(duì)于每一對(duì)的 i 和 j ,都有1<=i<=j<=n,此時(shí),我們只要確定了對(duì)于Ai..j=AiAi+1...Aj的乘積順序,即如何“劃分括號(hào)”,就決定了這一次乘積所需要的總計(jì)算次數(shù)。所以,我們只要找到一個(gè)乘積所需計(jì)算次數(shù)最小的計(jì)算順序(打括號(hào)方式),就是我們的最優(yōu)子結(jié)構(gòu)。
特別的是,我們應(yīng)該注意到,Ai...j的最后乘積結(jié)果是一個(gè)規(guī)模為【Pi-1*Pj】大小的矩陣。
我們前面講了這么多,要想找到最少的計(jì)算次數(shù),那么就必須要找到相對(duì)應(yīng)的計(jì)算順序,可是,計(jì)算順序是一個(gè)抽象的東西,那么在我們這個(gè)問(wèn)題里,計(jì)算順序的具體體現(xiàn)是什么呢?
讓我們這樣來(lái)想,無(wú)論我們以一個(gè)什么樣的乘法順序來(lái)計(jì)算,最后一步都是一樣的,即把最后生成的兩個(gè)中間矩陣Ai...k和Ak+1...j相乘,其中k可以是在合法范圍內(nèi)的任意一個(gè)值:
讓我們來(lái)舉個(gè)例子:
此時(shí),K=5,即應(yīng)用該種計(jì)算順序時(shí),最后一步的乘積狀態(tài)為A3...5*A6...6。
因此,決定最優(yōu)乘積計(jì)算順序的問(wèn)題就可以分解為下面兩個(gè)子問(wèn)題:
我們應(yīng)該在乘積序列中的哪一個(gè)地方使用大括號(hào)把該序列分成兩個(gè)子序列呢?(即K的值到底應(yīng)該設(shè)為多少?可以暴力列舉出所有合法的K值)
對(duì)于分割出來(lái)的兩個(gè)子乘積序列Ai...k和Ak+1..j,我們又該如何對(duì)他們?cè)龠M(jìn)行一步劃分呢?
此時(shí)問(wèn)題的“最優(yōu)子結(jié)構(gòu)”就已經(jīng)出現(xiàn)了,為了保證Ai...k*Ak+1...j是最優(yōu)的計(jì)算順序,則Ai...k和AK+1...j也應(yīng)該是由“最優(yōu)計(jì)算順序”計(jì)算出來(lái)的,因此,我們就可以遞歸的調(diào)用這個(gè)過(guò)程。
假設(shè)Ai...k的計(jì)算順序并不是最優(yōu)的,那么我們可以用更好的計(jì)算順序去替換,這樣就產(chǎn)生了悖論。
同樣的,如果Ak+1...j并不是最優(yōu)的,那么我們可以在找出另外一個(gè)更好的計(jì)算順序來(lái)替換他,此時(shí)也產(chǎn)生了悖論。
2️⃣找出最優(yōu)子結(jié)構(gòu)的遞推式。
就像我們學(xué)過(guò)的“0-1背包問(wèn)題”一樣,我們將會(huì)把“子問(wèn)題”的解決方法儲(chǔ)存到一個(gè)數(shù)組里頭。
對(duì)于:1≤i≤j≤n
我們定義:m[i,j]的值為計(jì)算Ai...j所需要要的最少的計(jì)算次數(shù),因此,這個(gè)最少計(jì)算次數(shù)的問(wèn)題可以用下面的遞歸式來(lái)描述:
證明如下:
此時(shí)有些同學(xué)可能會(huì)疑惑,為什么最后還要加上1個(gè)Pi-1PkPj
因?yàn)楦鶕?jù)我們前面的定義,Ai...k的乘積結(jié)果為一個(gè)規(guī)模為Pi-1 * Pk的矩陣,而Ak+1....Aj的乘積結(jié)果為一個(gè)規(guī)模為Pk * Pj的矩陣,所以,求Ai...j的最少乘積次數(shù)則為【Ai...k所需要的最少乘積次數(shù)】+【Ai+1...j所需要的最少乘積次數(shù)】+【中間生成的兩個(gè)臨時(shí)矩陣所需要的乘積次數(shù)】。
此時(shí)看似問(wèn)題已經(jīng)明朗了,但是!我們卻并不能夠確定K的值到底是多少?因?yàn)镵的值不同,會(huì)造成序列的劃分也不同,因此乘積次數(shù)也會(huì)不同,因此,我們只要找到某個(gè)K值,使得m[i,j]的值算出來(lái)是最小的,那么,我們的問(wèn)題就迎刃而解了。
但是問(wèn)題就是,咱們壓根就不知道K值取啥啊?
不用急,既然咱們不知道K是啥,那就一個(gè)一個(gè)把K的可能值都代進(jìn)去試一遍不就行了嗎?而且K的可能值也只有j-i種,因此我們就把這j-i都一個(gè)個(gè)的去試一遍,然后找出m[i,j]最小的那一個(gè)情況,此時(shí)的K值就是我們需要的,并且最小乘積次數(shù)也找到了,就是m[i,j]次。
讓我們?cè)賮?lái)看一看這個(gè)遞推公式:
8、”自下而上“計(jì)算最優(yōu)值
首先,讓我們來(lái)回憶一下有關(guān)于二維數(shù)組m[i,j]的定義,m[i,j]的值為計(jì)算Ai...j所需要要的最少的計(jì)算次數(shù)。
因此,我們的二維表為m[1..n,1..n],并且有i<=j。
現(xiàn)在最關(guān)鍵的是:
當(dāng)我們使用下面的等式:
來(lái)計(jì)算m[i,j]時(shí),我們必須首先得把m[i,k]和m[k+1,j]計(jì)算出來(lái),才能順利把m[i,j]計(jì)算出來(lái)。
對(duì)于被分割的兩個(gè)子序列,對(duì)應(yīng)的矩陣鏈的長(zhǎng)度都小于j-i+1。
因此,我們的算法以矩陣鏈長(zhǎng)度增長(zhǎng)的順序來(lái)計(jì)算,就像下面這樣子(假設(shè)我們需要計(jì)算m[1,n]):
9、動(dòng)態(tài)規(guī)劃時(shí)的注意事項(xiàng)
當(dāng)我們?cè)O(shè)計(jì)一個(gè)動(dòng)態(tài)規(guī)劃算法時(shí),我們需要注意下面兩點(diǎn):
1️⃣找到一個(gè)適當(dāng)?shù)淖顑?yōu)子結(jié)構(gòu)和在“表”中對(duì)應(yīng)的循環(huán)關(guān)系,例如我們現(xiàn)在討論的這個(gè)問(wèn)題:
2️⃣找到“表”中各“元素”之間的某種關(guān)系。
例如,當(dāng)我們需要計(jì)算表中某個(gè)位置的值時(shí),我們要想一想,這個(gè)值是不是依賴了其他的值?是不是得先計(jì)算出其他的某個(gè)或幾個(gè)值才能夠計(jì)算出這個(gè)值來(lái)?
在我們現(xiàn)在這個(gè)例子中就是:
我們需要計(jì)算m[i,j]的值,但是計(jì)算這個(gè)值之前,我們必須得先計(jì)算:m[i,k]和m[k+1,j]兩個(gè)元素的值。
10、樣例解析
假設(shè)我們現(xiàn)在有4個(gè)矩陣A1,A2,A3,A4組成的一個(gè)矩陣鏈,并且各矩陣的規(guī)模用數(shù)組P[ ]表示,P0=5,P1=4,P2=6,P3=2,P4=7。
現(xiàn)在,需要你計(jì)算矩陣A1A2A3A4乘積所需要的最少的乘法次數(shù),即求出m[1,4]的值。
解決方法:
使用動(dòng)態(tài)規(guī)劃算法解決,首先初始化數(shù)組m[i,j],為了便于同學(xué)們較為直觀的觀察數(shù)據(jù)的推導(dǎo)過(guò)程,數(shù)組m[i,j]我們不按照正常“表格”的方式展示,而是按照下面的“畫法”來(lái)展示:
正如圖中的標(biāo)識(shí)一樣,初始化時(shí)m[1,1],m[2,2],m[3,3],m[4,4]的值都為0,因?yàn)?個(gè)矩陣無(wú)法進(jìn)行乘法運(yùn)算,因此所需的計(jì)算次數(shù)當(dāng)然為0了。
1️⃣步驟一
首先,計(jì)算m[1,2],即A1A2所需要的最少計(jì)算次數(shù):
根據(jù)遞推式有:
此時(shí),K的取值范圍只有1個(gè)合法值,即K=1。此時(shí),A1A2的最少計(jì)算此時(shí)就是120次了,如下圖所示:
2️⃣步驟二
根據(jù)定義,計(jì)算m[2,3]的值,根據(jù)遞推式有:
此時(shí),K的合法值也只有1個(gè),即K=2,此時(shí)計(jì)算出來(lái)的值48就是A2A3所需要的最少計(jì)算次數(shù)啦!
3️⃣步驟三
計(jì)算m[3,4]的值,根據(jù)遞推式有:
此時(shí),K的合法值仍然只有1個(gè),即K=3,此時(shí)計(jì)算出來(lái)的最小值為84。
4️⃣步驟四
計(jì)算m[1,3]的值,根據(jù)定義的遞推式有:
此時(shí),K的合法值就有2個(gè)了,分別是1和2,也分別代表了兩種“切割”序列的方法。通過(guò)找出這兩種方法的最小值,即是此時(shí)最優(yōu)的解啦!其實(shí)和上面的計(jì)算是一樣的,只不過(guò)多了需要比較的一個(gè)情況而已。此時(shí),我們的二維數(shù)組m如下圖所示:
5️⃣步驟五
計(jì)算m[2,4]的值,根據(jù)定義有:
此時(shí),K的合法值也有2個(gè),也代表了A2..A4的兩種“切割”方法。這兩種“切割”方法所需要的計(jì)算次數(shù)的最小值為104,則這種方法是最優(yōu)解,值也是最優(yōu)值,即104。
6️⃣步驟六
計(jì)算m[1,4]的值,根據(jù)遞推式有:
此時(shí),K的合法值存在3種情況,分別為K=1,K=2,K=3,代表了3種“切割”方法,分別如下所示:
A1(A2A3A4)
(A1A2)(A3A4)
(A1A2A3)A4
按照老樣子,我們計(jì)算出m[1,4]的值為:158,即計(jì)算A1A2A3A4所需要的最少乘法次數(shù)為158次!
總結(jié)
以上是生活随笔為你收集整理的算法设计与分析——动态规划之矩阵连乘的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Image Processing Wav
- 下一篇: mysql性能测试工具——tpcc-my