動態規劃算法

動態規劃的關鍵點:

  1. 最優化原理,也就是最優子結構性質。這指的是一個最優化策略具有這樣的性質,無論過去狀態和決策如何,對前面的決策所形成的狀態而言,余下的決策必須構成最優策略,簡單來說就是一個最優化策略的子策略總是最優的,如果一個問題滿足最優化原理,就稱其有最優子結構性質。
  2. 無后效性,指的是某個狀態下的決策的收益,只與狀態和決策相關,與達到該狀態的方式無關。
  3. 子問題的重疊性,動態規劃將原來指數級的暴力搜索算法改進到了具有多項式時間復雜度的算法,其中的關鍵在于解決了冗余、重復計算的問題,這是動態規劃算法的根本目的。
  4. 總體來說,動態規劃算法就是一系列以空間換取時間的算法。

動態規劃使用

下面通過遞歸方式計算問題斐波那契數列(Fibonacci sequence)來闡述分治法不是銀彈。

斐波那契數列指的是這樣一個數列 0,1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368........


斐波那契數列數學表示

這個數列從第3項開始,每一項都等于前兩項之和。
下面給出遞歸實現的代碼:

    /**
     * 求解Fibonacci數列中第n個元素的值
     * @param n 斐波那契數列中的位置
     * @return Fibonacci數列中第n個元素的值
     */
    public int fibonacci(int n) {
        if(n<2) return n;
        if(n>=2) {
            return fibonacci(n-1)+fibonacci(n-2);
        }
        return -1;
    }

通過控制臺驗證下算法的計算結果和計算用時。

fibonacci 0 is 0                計算用時        0ms
fibonacci 1 is 1                計算用時        1ms
fibonacci 2 is 1                計算用時        0ms
fibonacci 3 is 2                計算用時        0ms
fibonacci 4 is 3                計算用時        0ms
fibonacci 5 is 5                計算用時        0ms
fibonacci 6 is 8                計算用時        0ms
fibonacci 7 is 13               計算用時        0ms
fibonacci 8 is 21               計算用時        0ms
fibonacci 9 is 34               計算用時        0ms
fibonacci 10 is 55              計算用時        0ms
fibonacci 11 is 89              計算用時        0ms
fibonacci 12 is 144             計算用時        0ms
fibonacci 13 is 233             計算用時        0ms
fibonacci 14 is 377             計算用時        0ms
fibonacci 15 is 610             計算用時        0ms
fibonacci 16 is 987             計算用時        0ms
fibonacci 17 is 1597            計算用時        1ms
fibonacci 18 is 2584            計算用時        0ms
fibonacci 19 is 4181            計算用時        0ms
fibonacci 20 is 6765            計算用時        0ms
fibonacci 21 is 10946           計算用時        0ms
fibonacci 22 is 17711           計算用時        0ms
fibonacci 23 is 28657           計算用時        1ms
fibonacci 24 is 46368           計算用時        0ms
fibonacci 25 is 75025           計算用時        1ms
fibonacci 26 is 121393          計算用時        1ms
fibonacci 27 is 196418          計算用時        1ms
fibonacci 28 is 317811          計算用時        3ms
fibonacci 29 is 514229          計算用時        2ms
fibonacci 30 is 832040          計算用時        4ms
fibonacci 31 is 1346269         計算用時        8ms
fibonacci 32 is 2178309         計算用時        11ms
fibonacci 33 is 3524578         計算用時        20ms
fibonacci 34 is 5702887         計算用時        29ms
fibonacci 35 is 9227465         計算用時        46ms
fibonacci 36 is 14930352        計算用時        73ms
fibonacci 37 is 24157817        計算用時        127ms
fibonacci 38 is 39088169        計算用時        186ms
fibonacci 39 is 63245986        計算用時        306ms
fibonacci 40 is 102334155       計算用時        505ms
fibonacci 41 is 165580141       計算用時        816ms
fibonacci 42 is 267914296       計算用時        1298ms
fibonacci 43 is 433494437       計算用時        2110ms
fibonacci 44 is 701408733       計算用時        3423ms
fibonacci 45 is 1134903170      計算用時        5525ms
fibonacci 46 is 1836311903      計算用時        9013ms
fibonacci 47 is -1323752223     計算用時        14382ms

可以看出,n=47是出現了int類型的越界(Integer.MAX_VALUE is 2147483647)這里需要注意,計算用時達到了恐怖的14秒多。斐波那契數列的值隨著增大進行指數級的增長,運行事件也是指數級的增長(n越大越能看出這一點)。


斐波那契數列-遞歸方法調用過程

動態規劃版本

正如魯迅先生的《狂人日記》中,孔乙己"回"字的四種寫法。動態規劃算法有兩種等價的實現方法。

  1. 帶備忘的自頂向下法(top-down with memoization),此方法仍按自然的遞歸形式編寫過程,但過程會保存每個子問題的解(通常保存在一個數組或者散列表中)。當需要一個子問題的解時,過程首先檢查是否已經保存過此解。如果是,則直接返回保存的值,從而節省了計算時間,否則,按通常的方式計算這個子問題。我們稱這個遞歸過程是帶備忘的(memoized),因為它“記住”了之前計算出的結果。
    以斐波那契數列的解法為例,代碼如下:
    long[] memo=new long[memoSize];
    public long topdown(int n) {
        if(n<0) return -1;
        if(n<2) return n;
        if(memo[n]>0) {
            return memo[n];
        }else {
            return memo[n]=topdown(n-1)+topdown(n-2);
        }

通過控制臺驗證下算法的計算結果和計算用時。

fibonacci 0 is 0        計算用時        0ms
fibonacci 1 is 1        計算用時        0ms
fibonacci 2 is 1        計算用時        0ms
fibonacci 3 is 2        計算用時        1ms
fibonacci 4 is 3        計算用時        0ms
fibonacci 5 is 5        計算用時        0ms
fibonacci 6 is 8        計算用時        0ms
fibonacci 7 is 13       計算用時        0ms
fibonacci 8 is 21       計算用時        0ms
fibonacci 9 is 34       計算用時        0ms
fibonacci 10 is 55      計算用時        0ms
fibonacci 11 is 89      計算用時        0ms
fibonacci 12 is 144     計算用時        0ms
fibonacci 13 is 233     計算用時        0ms
fibonacci 14 is 377     計算用時        0ms
fibonacci 15 is 610     計算用時        0ms
fibonacci 16 is 987     計算用時        0ms
fibonacci 17 is 1597        計算用時        0ms
fibonacci 18 is 2584        計算用時        0ms
fibonacci 19 is 4181        計算用時        0ms
fibonacci 20 is 6765        計算用時        0ms
fibonacci 21 is 10946       計算用時        0ms
fibonacci 22 is 17711       計算用時        0ms
fibonacci 23 is 28657       計算用時        0ms
fibonacci 24 is 46368       計算用時        0ms
fibonacci 25 is 75025       計算用時        0ms
fibonacci 26 is 121393      計算用時        0ms
fibonacci 27 is 196418      計算用時        0ms
fibonacci 28 is 317811      計算用時        0ms
fibonacci 29 is 514229      計算用時        0ms
fibonacci 30 is 832040      計算用時        0ms
fibonacci 31 is 1346269     計算用時        0ms
fibonacci 32 is 2178309     計算用時        0ms
fibonacci 33 is 3524578     計算用時        0ms
fibonacci 34 is 5702887     計算用時        0ms
fibonacci 35 is 9227465     計算用時        0ms
fibonacci 36 is 14930352        計算用時        0ms
fibonacci 37 is 24157817        計算用時        0ms
fibonacci 38 is 39088169        計算用時        0ms
fibonacci 39 is 63245986        計算用時        0ms
fibonacci 40 is 102334155       計算用時        0ms
fibonacci 41 is 165580141       計算用時        0ms
fibonacci 42 is 267914296       計算用時        0ms
fibonacci 43 is 433494437       計算用時        0ms
fibonacci 44 is 701408733       計算用時        0ms
fibonacci 45 is 1134903170      計算用時        0ms
fibonacci 46 is 1836311903      計算用時        0ms
fibonacci 47 is 2971215073      計算用時        0ms

  1. 自底向上法(bottom-up method),這種方法一般需要恰當定義子問題的“規?!钡母拍睿沟萌魏巫訂栴}的求解只依賴“更小的”子問題的求解。因而我們可以將子問題按規模排序,按由小到大的順序進行求解。當求解某個子問題時,它所依賴的那些更小的子問題都已經求解完畢,結果已經保存。每個子問題只需求解依次,當我們求解它(也是第一次遇到它)時,它的所有前提子問題都已求解完成。

動態規劃的解法-自底向上法

    long[] memo=new long[memoSize];
    public long     bottomup(int n) {
        if(n<0) return -1;
        if(n<=1) return n;
        memo[0]=0;
        memo[1]=1;
        if(n>1) {
            for(int i=2;i<=n;i++) {
                memo[i]=memo[i-1]+memo[i-2];
            }
        }
        return memo[n];
    }

通過控制臺驗證下算法的計算結果和計算用時。

fibonacci 0 is 0        計算用時        0ms
fibonacci 1 is 1        計算用時        0ms
fibonacci 2 is 1        計算用時        0ms
fibonacci 3 is 2        計算用時        0ms
fibonacci 4 is 3        計算用時        0ms
fibonacci 5 is 5        計算用時        0ms
fibonacci 6 is 8        計算用時        0ms
fibonacci 7 is 13       計算用時        0ms
fibonacci 8 is 21       計算用時        0ms
fibonacci 9 is 34       計算用時        0ms
fibonacci 10 is 55      計算用時        0ms
fibonacci 11 is 89      計算用時        0ms
fibonacci 12 is 144     計算用時        0ms
fibonacci 13 is 233     計算用時        0ms
fibonacci 14 is 377     計算用時        0ms
fibonacci 15 is 610     計算用時        0ms
fibonacci 16 is 987     計算用時        0ms
fibonacci 17 is 1597        計算用時        0ms
fibonacci 18 is 2584        計算用時        0ms
fibonacci 19 is 4181        計算用時        0ms
fibonacci 20 is 6765        計算用時        0ms
fibonacci 21 is 10946       計算用時        0ms
fibonacci 22 is 17711       計算用時        0ms
fibonacci 23 is 28657       計算用時        0ms
fibonacci 24 is 46368       計算用時        0ms
fibonacci 25 is 75025       計算用時        0ms
fibonacci 26 is 121393      計算用時        0ms
fibonacci 27 is 196418      計算用時        0ms
fibonacci 28 is 317811      計算用時        0ms
fibonacci 29 is 514229      計算用時        0ms
fibonacci 30 is 832040      計算用時        0ms
fibonacci 31 is 1346269     計算用時        0ms
fibonacci 32 is 2178309     計算用時        0ms
fibonacci 33 is 3524578     計算用時        0ms
fibonacci 34 is 5702887     計算用時        0ms
fibonacci 35 is 9227465     計算用時        0ms
fibonacci 36 is 14930352        計算用時        0ms
fibonacci 37 is 24157817        計算用時        0ms
fibonacci 38 is 39088169        計算用時        0ms
fibonacci 39 is 63245986        計算用時        0ms
fibonacci 40 is 102334155       計算用時        0ms
fibonacci 41 is 165580141       計算用時        0ms
fibonacci 42 is 267914296       計算用時        0ms
fibonacci 43 is 433494437       計算用時        0ms
fibonacci 44 is 701408733       計算用時        0ms
fibonacci 45 is 1134903170      計算用時        0ms
fibonacci 46 is 1836311903      計算用時        0ms
fibonacci 47 is 2971215073      計算用時        0ms

總結

同樣規模的斐波那契數列的計算問題,動態規劃版本的都能在很短的時間內計算完畢,遞歸的解決方案,在小于50的情況下就出現了十幾秒的計算情況,動態規劃的運行時間的提升很明顯。

動態規劃解決走臺階問題

有n級臺階,每次上一級或者兩級,問有多少種走完n級臺階的方法。

分析:動態規劃的實現的關鍵在于能不能準確合理的用動態規劃表來抽象出 實際問題。在這個問題上,我們讓f(n)表示走上n級臺階的方法數。
那么當n為1時,f(n) = 1,n為2時,f(n) =2,就是說當臺階只有一級的時候,方法數是一種,臺階有兩級的時候,方法數為2。那么當我們要走上n級臺階,必然是從n-1級臺階邁一步或者是從n-2級臺階邁兩步,所以到達n級臺階的方法數必然是到達n-1級臺階的方法數加上到達n-2級臺階的方法數之和。即f(n) = f(n-1)+f(n-2),我們用dp[n]來表示動態規劃表,dp[i],i>0,i<=n,表示到達i級臺階的方法數。

動態規劃的解法-自底向上法

    long[] memo=new long[memoSize];
    public long stepBottomup(int n) {
        if(n<0) return 0;
        if(n==1) return 1;
        if(n==2) return 2;

        memo[0]=1;
        memo[1]=2;
        if(n>1) {
            for(int i=2;i<n;i++) {
                memo[i]=memo[i-1]+memo[i-2];
            }
        }
        return memo[n-1];

    }

通過控制臺驗證下算法的計算結果和計算用時。

走臺階方案數      樓梯數 1    走法 is 1        計算用時        0ms
走臺階方案數      樓梯數 2    走法 is 2        計算用時        0ms
走臺階方案數      樓梯數 3    走法 is 3        計算用時        0ms
走臺階方案數      樓梯數 4    走法 is 5        計算用時        0ms
走臺階方案數      樓梯數 5    走法 is 8        計算用時        0ms
走臺階方案數      樓梯數 6    走法 is 13       計算用時        0ms
走臺階方案數      樓梯數 7    走法 is 21       計算用時        0ms
走臺階方案數      樓梯數 8    走法 is 34       計算用時        0ms
走臺階方案數      樓梯數 9    走法 is 55       計算用時        0ms
走臺階方案數      樓梯數 10   走法 is 89       計算用時        0ms
走臺階方案數      樓梯數 11   走法 is 144      計算用時        0ms
走臺階方案數      樓梯數 12   走法 is 233      計算用時        0ms
走臺階方案數      樓梯數 13   走法 is 377      計算用時        0ms
走臺階方案數      樓梯數 14   走法 is 610      計算用時        0ms
走臺階方案數      樓梯數 15   走法 is 987      計算用時        0ms
走臺階方案數      樓梯數 16   走法 is 1597     計算用時        0ms
走臺階方案數      樓梯數 17   走法 is 2584     計算用時        0ms
走臺階方案數      樓梯數 18   走法 is 4181     計算用時        0ms
走臺階方案數      樓梯數 19   走法 is 6765     計算用時        0ms
走臺階方案數      樓梯數 20   走法 is 10946        計算用時        0ms
走臺階方案數      樓梯數 21   走法 is 17711        計算用時        0ms
走臺階方案數      樓梯數 22   走法 is 28657        計算用時        0ms
走臺階方案數      樓梯數 23   走法 is 46368        計算用時        0ms
走臺階方案數      樓梯數 24   走法 is 75025        計算用時        1ms
走臺階方案數      樓梯數 25   走法 is 121393       計算用時        0ms
走臺階方案數      樓梯數 26   走法 is 196418       計算用時        0ms
走臺階方案數      樓梯數 27   走法 is 317811       計算用時        0ms
走臺階方案數      樓梯數 28   走法 is 514229       計算用時        0ms
走臺階方案數      樓梯數 29   走法 is 832040       計算用時        0ms
走臺階方案數      樓梯數 30   走法 is 1346269      計算用時        0ms
走臺階方案數      樓梯數 31   走法 is 2178309      計算用時        0ms
走臺階方案數      樓梯數 32   走法 is 3524578      計算用時        0ms
走臺階方案數      樓梯數 33   走法 is 5702887      計算用時        0ms
走臺階方案數      樓梯數 34   走法 is 9227465      計算用時        0ms
走臺階方案數      樓梯數 35   走法 is 14930352     計算用時        0ms
走臺階方案數      樓梯數 36   走法 is 24157817     計算用時        0ms
走臺階方案數      樓梯數 37   走法 is 39088169     計算用時        0ms
走臺階方案數      樓梯數 38   走法 is 63245986     計算用時        0ms
走臺階方案數      樓梯數 39   走法 is 102334155        計算用時        0ms
走臺階方案數      樓梯數 40   走法 is 165580141        計算用時        0ms
走臺階方案數      樓梯數 41   走法 is 267914296        計算用時        0ms
走臺階方案數      樓梯數 42   走法 is 433494437        計算用時        0ms
走臺階方案數      樓梯數 43   走法 is 701408733        計算用時        1ms
走臺階方案數      樓梯數 44   走法 is 1134903170       計算用時        0ms
走臺階方案數      樓梯數 45   走法 is 1836311903       計算用時        0ms
走臺階方案數      樓梯數 46   走法 is 2971215073       計算用時        0ms
走臺階方案數      樓梯數 47   走法 is 4807526976       計算用時        0ms

這里只給出其中的一種解法,至于另一種解法,大家嘗試的寫下。

以上,謝謝閱讀,希望你有所收獲!

算法導論公開課筆記(一)算法分析與設計
算法導論公開課筆記(二)快速排序和隨機化算法
算法導論公開課筆記(三)線性時間排序
算法導論公開課筆記(四)順序統計、中值
動態規劃算法

參考鏈接
動態規劃算法經典案例

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容

  • 原文: 常用的算法設計思想主要有動態規劃、貪婪法、隨機化算法、回溯法等等,這些思想有重疊的部分,當面對一個問題的時...
    josephok閱讀 1,145評論 0 3
  • 動態規劃學習-無資料 理論解釋http://www.cnblogs.com/steven_oyj/archive/...
    RavenX閱讀 1,027評論 0 2
  • 基本概念 動態規劃過程是:每次決策依賴于當前狀態,又隨即引起狀態的轉移。一個決策序列就是在變化的狀態中產生出來的,...
    羽恒閱讀 320評論 0 1
  • 動態規劃 動態規劃算法, Dynamic Programming簡稱DP,通常基于一個遞推公式及一個或多個初始狀態...
    御風逍遙閱讀 5,294評論 0 7
  • 對沒錯,今天我又分手了。每次分手都是一樣,因為小事吵得不可開交直至分手。真的挺累的,但我沒想到她不覺得我好過,這可...
    Lademon閱讀 188評論 0 0