動態規劃

1、前言

動態規劃和分治算法非常類似,都是通過組合子問題的解來求解原問題。分治算法將問題劃分為互不相交的子問題,而動態適應于子問題重疊的情況

動態規劃常用于求解“最優化問題”,這類問題有很多個解,我們希望尋找最優解(最大值或最小值)

通常按如下四個步驟來設計一個動態規劃算法:

  • 刻畫一個最優解的結構特征
  • 遞歸地定義最優解的值
  • 計算最優解的值,通常采用自底向上方法
  • 利用計算出的信息構造一個最優解

或者說,動態規劃有3個關鍵要素。

  • 1、最佳子問題(將復雜問題轉化成簡單問題)
  • 2、邊界條件(一般是當數據量極少情況下的結果,比如n==0或n==1時的情況)
  • 3、狀態轉移方程(考慮 n-1 和 n這兩種規模時,結果之間的推導)

2、鋼條切割問題

給定一段長為n的鋼條和一個價格表,求解收益最大的鋼條切割方案

鋼條價格

鋼條價格如上,怎么切割才能有最大收益呢?通過鋼條價格,我們能手動計算出鋼條最佳切割方案。

最優切割方案

定義長為n的鋼條切割最大收益為Rn,假設在k位置將鋼條切成兩段能獲得最大收益,那么這兩段k和n-k肯定也是最大收益,如果我們遍歷循環,可得到如下公式:

最大收益

最大收益為,不切割以及從1到n-1位置切割的收益最大值。

換一個角度重新考慮,如果從1到n-1位置切割,但左邊的鋼條不再切割,右邊的鋼條使用最佳方案切割。這樣得到的會不是也是最佳切割方案呢?

很明顯,這種做法也是正常的,想象最終切割結果,肯定也是符合這種模式的。這樣簡單的遞歸更利于編碼。

新公式

動態規劃的精髓在于保存子問題的解,以提高效率。在編碼中我們新定義Rn,保存n長度的最大收益,并采用自底向上方法,即先求R0,R1,再求其它,如果單純使用暴力遞歸的話,效率非常低。

  public static int[] steel(int[] p){
    int[] s = new int[p.length];
    s[0] = 0;
    int max = 0;
    //因為長度為0的鋼條,切割最大收益為0,S[0]已知,所以i從1開始
    for (int i = 1; i < p.length; i++) {
        max = 0;
        for (int j = 1; j <= i; j++) {
            //j也必須從1開始,如果從0開始,i等于1時,s[i-j]就等于s[1]了,而s[1]還是未知值
            if (max < (p[j] + s[i-j])) {
                max = p[j] + s[i-j];
            }
        }
        s[i] = max;
    }
    return s;
}

2、最大子數組和

給出一個數組,求最大子數組和。例如給出如下數組,最大子數組和為20

                  -2, 11, -4, 13, -5, -2

此問題解題思路和1不一樣。

仔細考慮,如果設長度為n的最大子數組和為Sn,那么Sn和Sn-1有什么關系呢?動態規劃最重要的思想就是將大問題分解為子問題,并由子問題求解。

直接考慮Sn和Sn-1,好像二者沒有任何關系,如果我們換個角度考慮,長度為n的數組,且以n結尾的最大子數組和為Sn,這么定義的話,那么根據Sn的值,如果Sn大于0,那么Sn+1等于Sn加上a[n],如果小于0,那么Sn+1等于a[n]。

公式為:

dp[i+1] = max(dp[i]+a[i+1] , a[i+1])

  public static int getMaxSubArray(int[] array){
    int[] b = new int[array.length];
    int max = 0;
    b[0] = array[0];
    max = b[0];
    for (int i = 1; i < array.length; i++) {
        if (b[i-1] > 0) {
            b[i] = b[i-1] + array[i];
        }else {
            b[i] = array[i];
        }
        if (max < b[i]) {
            max = b[i];
        }
    }
    return max;
}

3、結語

動態規劃還有其它經典問題,比如矩陣最少相乘次數,最長公共子序列,最優二叉搜索樹等等。本文只講了兩個簡單例子,簡述動態規劃的原理,可以更深入思考,二維的動態規劃問題解決,以加深理解。

以上代碼均已上傳至本人的github,歡迎訪問

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 動態規劃應用于子問題重疊的情況。對于公共子問題,分治算法會做很多不必要的工作,它會反復求解公共子問題。而動態規劃算...
    LRC_cheng閱讀 441評論 0 1
  • 《算法導論》這門課的老師是黃劉生和張曙,兩位都是老人家了,代課很慢很沒有激情,不過這一章非常有意思。更多見:iii...
    mmmwhy閱讀 5,298評論 5 31
  • 狀態轉移方程 從之前某個階段的某個或某些狀態狀態到下一個狀態之間的關系式,就叫做狀態轉移方程。 最優子結構 每個階...
    Myth52125閱讀 296評論 0 0
  • 目錄 動態規劃與分治法 2.動態規劃求解的最優化問題應該具備的兩個要素2.1 最優子結構2.2 子問題重疊 動態規...
    王偵閱讀 1,410評論 0 1
  • 第八十七章 回到J市的日子忽然就多了一點煙火氣,徐艾每天都能接到來自劉輝并不打擾的問候,他不會固定在某一個時刻打給...
    chief風閱讀 332評論 3 5