動態規劃——遞歸寫法和遞推寫法

1、什麼是動態規劃

  動態規劃(DP)是一種用來解決一類最優化問題的算法思想。簡單來講,動態規劃將一個複雜的問題分解成若干個子問題,經過綜合子問題的最優解來獲得原問題的最優解。算法

 

 

2、動態規劃的遞歸寫法

  以斐波那契(Fibonacci) 數列爲例,斐波那契數列的定義爲 F0=1,F1=1,Fn=Fn-1+Fn-2 (n≥2)。爲了避免重複計算,能夠開一個一維數組 dp,用以保存已經計算過的結果。代碼以下:數組

 1 int dp[maxn];  2 // 斐波那契數列遞歸寫法
 3 int F(int n) {  4     if(n == 0 || n==1)    return 1;    // 遞歸邊界
 5     if(dp[n] != -1)    return dp[n];    // 已經計算過 
 6     else {  7         dp[n] = F(n-1) + F(n-2);    // 計算F(n),並保存 
 8         return dp[n];                // 返回 F(n) 結果 
 9  } 10 }

 

 

 

3、 動態規劃的遞歸寫法

  以經典的數塔問題爲例,以下圖所示,將一些數字排成數塔的形狀,其中第一層有一個數字,第二層有兩個數字……第 n 層有 n 個數字。如今要從第一層走到第 n 層,每次只能走向下一層鏈接的兩個數字中的一個,問:最後將路徑上全部數字相加後獲得的和最大是多少?優化

  

  不妨令 dp[i][j] 表示從第 i 行第 j 個數字出發到達最底層的全部路徑中能獲得的最大和,在定義了這個數組後,dp[1][1] 就是最終想要的答案。spa

  若是想求出 dp[i][j],那麼必定要先求出它的兩個子問題「從位置 (i+1,j) 到達最底層的最大和 dp[i+1][j]」和「從位置 (i+1,j+1) 到達最底層的最大和 dp[i+1][j+1]」,即進行了一次決策:走左下仍是右下。寫成式子就是:code

              dp[i][j] = max(dp[i+1][j], dp[i+1][j+1]) + f[i][j]blog

  其中 f[i][j] 存放第 i 層的第 j 個數字。代碼以下:繼承

 1 /*
 2  動態規劃的遞推寫法  3 */
 4 
 5 #include <stdio.h>
 6 #include <string.h>
 7 #include <math.h>
 8 #include <stdlib.h>
 9 #include <time.h>
10 #include <stdbool.h>
11 
12 #define maxn 1000
13 int f[maxn][maxn], dp[maxn][maxn]; 14 
15 // 較大值 
16 int max(int a, int b) { 17     return a>b ? a : b; 18 } 19 
20 int main() { 21     int n; 22     scanf("%d", &n); 23     int i, j; 24     for(i=1; i<=n; ++i) { 25         for(j=1; j<=i; ++j) { 26             scanf("%d", &f[i][j]);        // 輸入數塔 
27  } 28  } 29     // 邊界
30     for(j=1; j<=n; ++j) { 31         dp[n][j] = f[n][j]; 32  } 33     // 從第 n-1 層往上計算 dp[i][j]
34     for(i=n-1; i>=1; --i) { 35         for(j=1; j<=i; ++j) { 36             dp[i][j] = max(dp[i+1][j], dp[i+1][j+1]) + f[i][j]; 37  } 38  } 39     printf("%d\n", dp[1][1]);            // dp[1][1] 即爲須要的答案 
40 
41     return 0; 42 }

   

 

  下面指出兩對概念的區別:遞歸

  1.  分治與動態規劃。分治和動態規劃都是將問題分解爲子問題,而後合併子問題的解獲得原問題的解。可是不一樣的是,分治法分解出的子問題是不重疊的,所以分治法解決的問題不擁有重疊子問題,而動態規劃解決的問題擁有重疊子問題。另外,分治法解決的問題不必定是最優化問題,而動態規劃解決的問題必定是最優化問題。ci

  2.  貪心與動態規劃。貪心和動態規劃都要求原問題必須擁有最優子結構。兩者的區別在於,貪心法經過一種策略直接選擇一個子問題去求解,沒被選擇的子問題就不去求解了,直接拋棄。也就是說,它老是隻在上一步選擇的基礎上繼續選擇,所以整個過程以一種單鏈的流水方式進行。而動態規劃老是從邊界開始向上獲得目標問題的解。也就是說,它老是會考慮全部子問題,並選擇繼承能獲得最優結果的那個,對暫時沒被繼承的子問題,因爲重疊子問題的存在,後期可能會再次考慮它們,所以還有機會成爲全局最優的一部分,不須要放棄。    string

相關文章
相關標籤/搜索