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