1. 程式人生 > 其它 >動態規劃(矩陣連乘)學習筆記

動態規劃(矩陣連乘)學習筆記

動態規劃的思想:

  • 動態規劃演算法與分治法類似,其基本思想也是將待求解問題分解成若干個子問題
  • 動態規劃分解得到的子問題往往不是相互獨立的。不同子問題的數目常常只有多項式量級

動態規劃的基本要素:

  • 最優子結構
    • 矩陣連乘計算次序問題的最優解包含著其子問題的最優解———最優子結構性質
    • 以自底向上的方式遞迴地從子問題的最優解逐步構造出整個問題的最優解
  • 子問題的重疊性質
    • 對每一個子問題只解一次,而後將其解儲存在一個表格中(可急

分治法和動態規劃的區別:

  • 兩者都是通過將整個問題逐步劃分為一個個小的問題進行解決
    • 分治法:每個子問題都是相互獨立(因此會出現很多的重複計算)
    • 動態規劃:每個子問題不是相互獨立,並會將子問題的解進行儲存,避免重複計算,從而提高效率
  • 動態規劃從部分到整天,而分治思想從整體到部分

例如:

斐波那契數列:

有很多子問題會被重複計算,從而降低了效率

矩陣連乘

矩陣連乘是動態規劃的一個簡單的應用

下面運用了3種不同的方式,對比動態規劃與遞迴的區別,已經動態規劃思想是如何得到應用的

遞迴:

recurMatrixChain(int i, int j){
    if(i==j) return 0
    int u = recurMatrixChain(i+1,j)+p[i-1]*p[i]*p[j]
    S[i][j]=i
    for(int k=i+1;k<j;k++)
        int t 
= recurMatricChain(i,k)+recurMatricChain(k+1,j)+p[i-1]*p[i]*p[j] if(t<u){ u=t S[i][j]=k } return u

method1,method2,method3 就是這道題遞迴的劃分思想

備忘錄:

相比於遞迴,備忘錄就是增添一個數組m,去記錄每次計算的結果,從而減少了很多重複的計算,提高了效率

備忘錄是自上而下的記錄方式

m <- 0
private static int lookupChain( i, j){
    
#判斷子問題是否已經執行 if(m[i][j] >0) return m[i][j] if(i==j) return 0 int u = lookupChain(i+1,j)+p[i-1]*p[i]*p[j] S[i][j]=i for(int k=i+1;k<j;k++) int t = lookupChain(i,k)+lookupChain(k+1,j)+p[i-1]*p[i]*p[j] if(t<u){ u=t S[i][j]=k } #記錄每個已經運算的子問題 m[i][j] = u return u

動態規劃:

相比於遞迴和備忘錄,動態規劃則採用的是自下而上的計算思想,和儲存方式

public static void matrixChain(int[] p, int[][] m, int[][] s){
    int n=p.length-1
#計算最小規模子問題
    for(int i=1;i<=n;i++) m[i][i] =0
#計算規模從2到n,規模逐漸增大的各子問題
    for(int r=2;r<=n;r++){
#按照r規模劃分,
#A1,A2,A3,A4 
#當r = 2 時
#for劃分為(A1,A2)(A2,A3)(A3,A4)
        for(int i=1;i<=n-r+1;i++){
            int j=i+r-1;
# j始終比i大r-1
            m[i][j] = m[i+1][j]+p[i-1]*p[i]*p[j]
            s[i][j]=i
#計算r個規模中最小的計算量
#例如(A1,A2,A3)
#先計算A1(A2,A3) 的大小
#再計算(A1,A2)A3 的大小
#並比較,留小的那個值
            for(int k=i+1;k<j:k++){
                int t =m[i][k] + m[k+1][j]+p[i-1]*p[k]*p[j]
                if(t<m[i][j]){
                    m[i][j] =t
#計算此時括號的位置
                    s[i][j] =k;