動態規划算法入門


  1. 動態規划算法定義:

    動態規划,英文描述為Dynamic programming. 是一種可以把原始問題分解為若干相關聯的子解問題,並通過求取和保存子問題的解,獲得原問題的解。

    動態規划算法可以解決的問題通常包含如下特征:

  • 重疊子問題
  • 最優子結構

  對於第一個特征,比較容易理解,即分解的若干子問題,包含着重復的解。舉例如:斐波那契數列,F(n) = F(n-1) + F(n-2), 求解的F(n-1)的過程中,包含着求解F(n-2)的結果。

      對於第二個特征,參考網上的說法為:

       假設當前決策結果是f[n],則最優子結構就是要讓f[n-k]最優,最優子結構性質就是能讓轉移到n的狀態是最優的,並且與后面的決策沒有關系,即讓后面的決策安心地使用前面的局部最優解的一種性質。

關鍵字解讀為:  

  •  當前的決策與后面的決策是無關的,  
  •   f[n-k]是最優的,轉移到f[n]的狀態是最優的

    2. 動態規划算法的一般步驟和難點

  使用動態規划算法解決問題的一般步驟是:

  •  找到問題的最優解的性質,用數學公式或者算法描述
  •  拆解子問題,確定問題的遞推結構,保證可以收斂。

  用知乎大神們的總結就是:找到問題的狀態描述和狀態轉移方程。

    3. 動態規划算法的分類和理解

  根據我的理解,以及網上的說法,我把動態規划算法分為三個類別和層次:

  • 簡單動態規划算法,即狀態方程是用一個維度的變量的描述的,常見的問題如:斐波那契數列,爬台階問題等

  爬台階問題問題描述: 有一座高度是10級台階的樓梯,從下往上走,每跨一步只能向上1級或者2級台階。要求用程序來求出一共有多少種走法。

  狀態描述: 我們使用變量n表示台階的級數,F(n)表示n級台階一共有多少種走法

  狀態轉移方程與問題分解: 根據每次能跨越的台階數目:1級台階或者2級台階,因為走到N級台階之前,人一定是處於N-1級台階或者N-2級台階。F(n)的走法,一定是n-1級別的台階的所有的走法和n-2級別台階的所有走法之和。

  F(n) = F(n-1) + F(n-2);  關於狀態的分解,更詳細的說明,可以看這篇文章:http://blog.csdn.net/baidu_37107022/article/details/73188963。 作者講的非常的通俗易懂。佩服這么辛苦的編輯。

     Java的代碼實現

public static int  getSumStep(int n){
        if(n < 1){
            return 0;
        }
        else if(n == 1){
            return 1;
        }
        else if(n == 2){
            return 1;
        } else {
            int f1 = 1;
            int f2 = 1;
            int f = 0;
            for(int i=3; i<=n; ++i){
                f = f1 + f2;
                f1 = f2;
                f2 = f;
            }
            return f;
        }
    }
  • 二維的變量變化的動態規划算法,即最優解和遞推關系需要兩個維度變量來描述的,比如01背包問題,兩個字符串的公共子序列問題

     這類問題通常需要兩個維度的變量,狀態的描述比較晦澀,不容易理解,遞推關系不是很直觀。我自己的學習方法是牢記一個例子,這里以01背包問題為例:

問題描述:有編號分別為a,b,c,d的四件物品,它們的重量分別是2,3,4,5,它們的價值分別是3,4,5,6,現在給你個承重為8的背包,如何讓背包里裝入的物品具有最大的價值總和?

編號 a b c d
w(重量) 2 3 4 5
v(價值) 3 4 5 6

     

    這類問題我覺得抽象的比較好的一篇文章是這篇文章:

     http://www.cnblogs.com/Christal-R/p/Dynamic_programming.html, 不過我當時是在手機上看到的,好了好久才找到這篇文章。

    作者抽象的實在太好了,我覺得我都沒法用語言去寫出這么嚴格的數學公式表達和證明,這里就不贅述了。

    下面寫的,僅供自己理解使用, 總結下來就是:

    Xi的取值為0,1 ;表示物品是否選取, i的取值為 1,2,3,4表示a,b,c,d4見物品

    Wi表示物品的重量, w1=2, 表示 a物品的重量為2 

    Vi 表示物品的價值, v3 - 5, 表示物品c的價值為5;

    

      其中n 表示 前 n個物品,這個表述是很重要的,如果是第一次思考這個問題,很多人都會卡在這里,

      m表示背包的重量;

      約束條件: 

     

       遞推關系: 

       

      第一個公式表示  n == 0 或者 m == 0 ,  即物品的數量為0 或者背包的重量為0的時候,可以算是起始條件

      第二個公式表示: 表示包的重量小於新增加的物品, 新增加的物品,無法裝入,如下圖的F(2, 2 ) 表示前兩個物品,包的重量2 ,  2  < (w[2] = 3), 此時F(2,2 )= F(1 , 2) = 3;

      第三個公式表示: 包的重量能夠容納w[n],新增加的物品,這個時候,最大的價值就要在 F(n-1, m) 和 F(n-1, m- Wn) + V[n]) 這兩個價值中選取了。

      舉例如下圖打表的 F(4, 8),  因為 8 - (w[n] ,4) > 0 F(4, 8) = max(F(3, 8), F(3,3 ) + v[4]) = 10;

      表的過程如下:

      

      java代碼如下:

     

public static int getMaxValue(int[] wArray, int[] vArray, int bagWeight){

        int lenght = wArray.length;
        // init set zero
        // manipulator the talbe
        int [][] result = new int[lenght+1][bagWeight+1];
        int [][] bRecord = new int[lenght+1][bagWeight+1];

        for(int i=1; i<= lenght; ++i){
            for(int j=1;j <= bagWeight; ++j){
                if(j<wArray[i-1]){
                    result[i][j] = result[i-1][j];
                    bRecord[i][j] = 1;
                }else{

                    if( result[i-1][j] > result[i-1][j-wArray[i-1]]+ vArray[i-1]) {
                        result[i][j] = result[i-1][j];
                        bRecord[i][j] = 1;
                    } else{
                        result[i][j] = result[i-1][j-wArray[i-1]]+ vArray[i-1];
                        bRecord[i][j] = 2;
                    }

                }
            }
        }

        return result[lenght][bagWeight];
        //return bRecord;
    }

     需要注意的是因為java數組的索引下標為從0,開始,所以

   result[i][j] = result[i-1][j-wArray[i-1]]+ vArray[i-1];

brecord是記錄操作的過程,用於回溯使用,這部分代碼,后續實現。
  • 帶有額外條件的動態規划問題(這類問題,我暫時還沒有學習)

    4.   動態規划與分治法的區別和聯系

      分治法是指將問題划分成一些獨立地子問題,遞歸地求解各子問題,然后合並子問題的解而得到原問題的解。

     動態規划適用於子問題獨立且重疊的情況,也就是各子問題包含公共的子子問題。動態規划算法對每個子子問題只求解一次,將其結果保存在一張表中,從而避免每次遇到各個子問題時重新計算答案。

     分治法主要在於子問題的獨立性,比如排序算法等, 動態規划算法主要適用於處理 子問題重復性和最優子結構的的問題。  

     目前的理解還比較淺顯,只能先這么記錄了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM