1. 程式人生 > >漫談演算法 動態規劃 Dynamic Programming

漫談演算法 動態規劃 Dynamic Programming

Dynamic Programming一直以來是自己比較弱的一部分,希望可以在這一塊有所提升。
動態規劃,Dynamic Programming。這裡的programming沒有翻譯成程式設計,是因為,這裡的programming的意思是指一個tabular method。其實這也暗示了DP的本質,用一個table儲存子問題的中間結果。(後面會有例子具體介紹)

和分治演算法比較類似,但不同的是分治演算法把原問題劃歸為幾個相互獨立的子問題,從而一一解決,而動態規劃則是針對子問題有重疊的情況的一種解決方案。

目前design DP主要有兩個思路:

一個是利用recursive method

,即首先把問題用遞迴的方法解決,然後用一個table儲存recursive中的中間結果,這不就避免了遞迴中重複計算的低效了嗎?遇到需要計算以前計算過的東西,直接查表就OK,總之一句話,先寫recursive,然後比葫蘆畫瓢基本就能把DP的方法寫出來。這裡的難點是如何找到recursive。演算法導論裡面也給的是這個思路。下面的前三個例子全部出自《演算法導論》。

另一個思路是exhaust search,這個好像是我們老師發明的方法,這裡有篇Kirk的論文, How to design dynamic programming algorithms sans recursion 有興趣的大家可以仔細研究一下,我下面也會簡單舉例介紹一下這個方法。

下面的例子中多數程式碼都是虛擬碼,旨在illustrate idea。同時節省時間。程式碼中都省去了backtrack的過程,即只得到了optimal solution的值,省去了如何construct optimal solution的過程。這個一般用一個數組記錄一下就OK了。

轉載於:http://www.cnblogs.com/Gavin_Liu/archive/2011/04/13/2011214.html

先來個比較簡單的例子(其實後面的也不難O(∩_∩)O~)

例:Rod-cutting problem(切木頭問題。感覺翻譯過來怎麼就變了味呢?囧。。。)

Input:有一個長n米的木頭,和一個price table,table如下:

長度 i 1  2  3  4  5  6 。。。

價格 Pi 1  5  8  9  10  17。。。

意思很明顯,就是長度為1米的木頭可以買1元,長5米的可以賣10元,依次類推

Output:找一個cut的方法,使最後賺的錢最多。

很顯然,這個遞迴的主要思路是我切一刀之後,分成兩段,一段我按table的價錢賣了,另一段我當成一個新的子問題,繼續作為我的函式的新的引數,這樣不就遞迴了嗎?(__) 但是問題是這一刀怎麼切,沒錯,我們就來個找最大值,即max_{i =1 to n} Pi + Cut(n-i).

所以,遞迴函式應該是:

Cut(P, n){ //P 就是我的table,n是木頭長度
   
  if n == 0
      return 0;
  q = -infinity
  for i = 1 to n
      q = max(q,P[i]+Cut(P,n-i))
  return q;
  

}

然後,根據這個recursive寫DP

Cut(P, n){

  for(int i = 1; i<=n; i++){

    q = -infinity;

    for(int j = 1; j<=i; j++)

      q = max(q, P[j] + r[i-j]);

    r[i] = q;

  }

  return r[n];

}