動態規劃:通過組合子問題的解來求解原問題,常用來求解最優化問題。常用來解決以下幾類問題,但不是說遇到類似問題必須用動態規劃來解決,可以往這方面去想:
1.計數問題,如有多少種方式走到右下角,有多少種方法選出k個數使得和是sum;
2.求最大最小值,如從左上角走到右下角路徑的最大數字和
3.求存在性,如取石頭遊戲,先手能否必勝,如能不能選出k個數使得和是sum
動態規劃問題的四個解決步驟:
1.確定狀態:研究最優策略的最後一步是什麼,並化為子問題
2.轉移方程:根據子問題定義直接得到
3.初始條件和邊界條件
4.計算順序,從已經推導出的部分去得到未知部分
下面利用一些例子來說明動態規劃問題如何解決
第乙個問題:給定乙個整數陣列 nums ,找到乙個具有最大和的連續子陣列(子陣列最少包含乙個元素),返回其最大和。如陣列[-2,1,-3,4,-1,2,1,-5,4],最大連續子陣列 [4,-1,2,1] 的和最大,為 6。
這是乙個求最大最小值型別,按四個解決步驟來進行:
假設陣列a有n+1個數,序號從0開始,sum陣列存放當前元素結尾的最大連續子陣列的和,如sum[2]表示以序號2元素結尾的最大連續子陣列的和。
首先,確定狀態。最優策略的最後一步是判斷以a[n]結尾的連續子陣列的最大和,有兩種可能,a[n]+sum[n-1]和a[n],如果a[n]+sum[n-1]大於a[n],則sum[n] = a[n]+sum[n-1],反之sum[n] = a[n]
第二步,狀態轉移矩陣。sum[n-1]>0,sum[n] = a[n]+sum[n-1],反之,sum[n] = a[n]
第三步,初始條件,sum[0] = a[0],只有乙個元素,則最大值為本身
最後一步,計算順序。從第二步可以發現,計算順序是從左到右。
具體**
int
maxsubarray
(vector<
int>
& nums)
return max;
}
第二個問題:乙個機械人位於乙個 m x n 網格的左上角 (起始點在下圖中標記為「start」 )。機械人每次只能向下或者向右移動一步。機械人試圖達到網格的右下角(在下圖中標記為「finish」)。問總共有多少條不同的路徑?這是乙個計數問題,假設路徑數量矩陣a[m-1][n-1],序號從0開始。
第一步,確定狀態。最後一步一定是判斷到finish這個格仔需要多少步。由於只能向下或者像右走,那麼走到finish這個格仔之前的那步不是它左邊那個格仔就是它上面那個格仔。所有走到finish格仔的路徑數量等於走到它左邊格仔的路徑數量加上走到它上面格仔的路徑數量。
第二步,狀態轉移方程,a[m-1][n-1] = a[m-1][n-2] + a[m-2][n-1]
第三步,初始條件和邊界條件。初始條件為a[0][0] = 1, start格仔只有一種到達方法,然後是第一行與第一列也只有一種到達方式,因為只能一直往右走或者一直往下走才能到達。
最後一步,計算順序。從狀態轉移矩陣可以發現計算順序是從左往右,從上往下。
具體**
int
uniquepaths
(int m,
int n)
}return r[m -1]
[n -1]
;}
從兩個例子中可以發現,最優策略結果的計算可以轉化為乙個或多個子問題,而子問題的解也是該子問題的最優的解,並且後面問題的計算過程不會影響到前面子問題的結果(無後序性)。如果採用迭代的方法來計算結果,會有很多很多重複計算,而通過動態規劃,可以避免這些重複計算,只需要計算一次,從而大大降低了時間。 貪心演算法和動態規劃
貪心演算法 在求解問題時,總是做出在當前看來做好的選擇,所以它是區域性最優解,試圖通過區域性最優推出全域性最優。需要注意的是貪心演算法沒有固定的演算法框架,演算法設計的關鍵是選擇貪心策略,其必須具備無後效性,即某個狀態以後的過程不會影響以前的狀態,只與當前狀態有關。常見的用貪心演算法解決的問題,比如...
貪心演算法 and 動態規劃
動態規劃dynamic programming 貪心演算法,又名貪婪法,是尋找最優解問題的常用方法 步驟1 從某個初始解出發 步驟2 採用迭代的過程,當可以向目標前進一步時,就根據區域性最優策略,得到一部分解,縮小問題規模 步驟3 將所有解綜合起來。假設你開了間小店,不能電子支付,錢櫃裡的貨幣只有 ...
動態規劃和貪心演算法對比
動態規劃和貪心演算法都是一種遞推演算法 均有區域性最優解來推導全域性最優解 不同點 貪心演算法 1.貪心演算法中,作出的每步貪心決策都無法改變,因為貪心策略是由上一步的最優解推導下一步的最優解,而上一部之前的最優解則不作保留。2.由 1 中的介紹,可以知道貪心法正確的條件是 每一步的最優解一定包含上...