動態規劃與分治法類似,都是通過組合子問題的解來求解原問題。分治方法將問題劃分為互不相交的子問題,遞迴的求解子問題,再將它們組合起來,求出原問題的解。與之相反,動態規劃應用於子問題重疊的情況,不同的子問題具有公共的子子問題。這個時候,分治演算法會做許多不必要的工作,它會反覆的求解那些公共子子問題,而動態規劃則對每個子問題只求解一次。舉例來說,在之前的文章《排序演算法總結》中,我們介紹了一些採用分治策略的演算法,比如歸併演算法,快速排序演算法等,它們會把陣列分為兩個部分,兩個部分是不相交的,然後分別處理每個部分,這裡就不存在重疊子問題。但是對於爬樓梯問題,如果採用遞迴解法,那麼當我們算第4層的時候,會計算第3層與第2層,當我們計算第3層時,會計算第2層與第1層,可見第2層被重複計算了,這種情況下效率會很低,動態規劃則能很好的處理這種問題。
設計乙個動態規劃的步驟:
1.刻畫乙個最優解的結構特徵
2. 遞迴的定義最優解的值
3.計算最優解的值
4.利用計算資訊構造出乙個最優解
下面我們具體看一下。
刻畫乙個最優解的結構特徵是第一步,也是最難的一步了,動態規劃威力巨大,可不見得人人都能想到,這一點還要「靠感覺」,但是也有一些小的技巧幫助我們啟發思維。首先動態規劃有一維的,也有二維的,還有三維的(四維的很少見),這跟座標系一樣不同的維度,如果只涉及乙個點集就是一維的,如果涉及到兩個點集元素之間的關係則是二維的。。。,在解決動態規劃問題時也有類似的規律。如果我們的問題只涉及乙個物件,比如前面提到的爬樓梯問題,那麼它很有可能是一維的,如果涉及到兩個物件,比如最長公共子串行問題,那麼它一般是二維的,這時它的結構就是int dp = new int[len1][len2]的形式。當然,這也不能太絕對,leetcode上有一道題目(後面會介紹),涉及到三個物件,但是結果卻是用二維dp解決的,這種情況一般是因為三者之間有固定的關係,可以使我們消掉一維,前面提到的這道題就是這種情況。還需要說明一點,我們上句話中提到的」物件「要正確理解,比如並不一定兩個字串才算兩個物件,乙個字串也可能是兩個」物件「,這主要是由我們研究的問題的結構決定的,比如找乙個字串中的回文子串問題。另外,我們發現動態規劃與高中學習的數學歸納法有些類似,這也啟發我們在解決這類問題時可以從乙個小規模的問題開始嘗試。我還常用的另一種方法就是假設,比如通過前面介紹的,我認為這是乙個二維動態規劃問題,那麼我就會假設dp[len1][len2]就是我最終要求的解,然後從這個假設開始倒著推,看看能不能有什麼新的發現。
在解決了上面的問題之後,動態規劃還有一點可能會遇到的困難就是解的構造。比較複雜的就是通過dfs進行最終解的構造了,這種情況多加練習就可以了。
接下來一篇部落格會通過具體的題目來加深dp的理解和應用。 參考
《演算法導論》
動態規劃專題
多階段過程轉化為一系列單階段問題,利用各階段之間的關係,逐個求解,創立了解決這類過程優化問題的新方法 動態規劃 個人的理解 就是處於當前決策時要依賴前面的已知情況,將看似 連續無統一標準解決方案 的問題分割成多個 可以商量的 的決策過程。商量就是依靠已知的情況覺得未知 那麼什麼問題才可以用到動態規劃...
動態規劃專題
這個題,初學之時,老師教我們用分治演算法,分三路 在左邊子陣列 在右邊子陣列以及跨越中線,其實用動態規劃已經很簡單了,看狀態轉移方程就明白了 dp i beginarr i quad i 0 max quad otherwise end def maximum subarr arr if not a...
動態規劃專題
例一 有一段樓梯有10級台階,規定每一步只能跨一級或兩級,要登上第10級台階有幾種不同的走法?1 include 2 include 3 include 4 include5 using namespace std 6int solution int n 遞迴做法713 int dp 11 14in...