前言:
書中列舉四個常見問題,分析如何采用動態規划方法進行解決。今天把動態規划算法總結一下。關於四個問題的動態規范分析過程可以參考前面的幾篇日志,鏈接如下:
裝配線調度問題:http://www.cnblogs.com/Anker/archive/2013/03/09/2951785.html
矩陣鏈乘問題:http://www.cnblogs.com/Anker/archive/2013/03/10/2952475.html
最長公共子序列問題:http://www.cnblogs.com/Anker/archive/2013/03/11/2954050.html
最優二叉查找樹問題:http://www.cnblogs.com/Anker/archive/2013/03/13/2958488.html
1、基本概念
動態規划是通過組合子問題的解而解決整個問題的,通過將問題分解為相互不獨立(各個子問題包含有公共的子問題,也叫重疊子問題)的子問題,對每個子問題求解一次,將其結果保存到一張輔助表中,避免每次遇到各個子問題時重新計算。動態規划通常用於解決最優化問題,其設計步驟如下:
(1)描述最優解的結構。
(2)遞歸定義最優解的值。
(3)按自底向上的方式計算最優解的值。
(4)由計算出的結果構造出一個最優解。
第一步是選擇問題的在什么時候會出現最優解,通過分析子問題的最優解而達到整個問題的最優解。在第二步,根據第一步得到的最優解描述,將整個問題分成小問題,直到問題不可再分為止,層層選擇最優,構成整個問題的最優解,給出最優解的遞歸公式。第三步根據第二步給的遞歸公式,采用自底向上的策略,計算每個問題的最優解,並將結果保存到輔助表中。第四步驟是根據第三步中的最優解,借助保存在表中的值,給出最優解的構造過程。
動態規划與分治法之間的區別:
(1) 分治法是指將問題分成一些獨立的子問題,遞歸的求解各子問題。
(2) 動態規划適用於這些子問題不是獨立的情況,也就是各子問題包含公共子問題。
2、動態規划基礎
什么時候可以使用動態規范方法解決問題呢?這個問題需要討論一下,書中給出了采用動態規范方法的最優化問題中的兩個要素:最優子結構和重疊子結構。
1)最優子結構
最優子結構是指問題的一個最優解中包含了其子問題的最優解。在動態規划中,每次采用子問題的最優解來構造問題的一個最優解。尋找最優子結構,遵循的共同的模式:
(1)問題的一個解可以是做一個選擇,得到一個或者多個有待解決的子問題。
(2)假設對一個給定的問題,已知的是一個可以導致最優解的選擇,不必關心如何確定這個選擇。
(3)在已知這個選擇后,要確定哪些子問題會隨之發生,如何最好地描述所得到的子問題空間。
(4)利用“剪貼”技術,來證明問題的一個最優解中,使用的子問題的解本身也是最優的。
最優子結構在問題域中以兩種方式變化:
(1)有多少個子問題被使用在原問題的一個最優解中。
(2)在決定一個最優解中使用哪些子問題時有多少個選擇。
動態規划按照自底向上的策略利用最優子結構,即:首先找到子問題的最優解,解決子問題,然后逐步向上找到問題的一個最優解。為了描述子問題空間,可以遵循這樣一條有效的經驗規則,就是盡量保持這個空間簡單,然后在需要時再擴充它。
注意:在不能應用最優子結構的時候,就一定不能假設它能夠應用。 警惕使用動態規划去解決缺乏最優子結構的問題!
使用動態規划時,子問題之間必須是相互獨立的!可以這樣理解,N個子問題域互不相干,屬於完全不同的空間。
2)重疊子問題
用來解決原問題的遞歸算法可以反復地解同樣的子問題,而不是總是產生新的子問題。重疊子問題是指當一個遞歸算法不斷地調用同一個問題。動態規划算法總是充分利用重疊子問題,通過每個子問題只解一次,把解保存在一個需要時就可以查看的表中,每次查表的時間為常數。
由計算出的結果反向構造一個最優解:把動態規划或者是遞歸過程中作出的每一次選擇(記住:保存的是每次作出的選擇)都保存下來,在最后就一定可以通過這些保存的選擇來反向構造出最優解。
做備忘錄的遞歸方法:這種方法是動態規划的一個變形,它本質上與動態規划是一樣的,但是比動態規划更好理解!
(1) 使用普通的遞歸結構,自上而下的解決問題。
(2) 當在遞歸算法的執行中每一次遇到一個子問題時,就計算它的解並填入一個表中。以后每次遇到該子問題時,只要查看並返回表中先前填入的值即可。
3、總結
動態規划的核心就是找到問題的最優子結構,在找到最優子結構之后的消除重復子問題。最終無論是采用動態規划的自底向上的遞推,還是備忘錄,或者是備忘錄的變型,都可以輕松的找出最優解的構造過程。