經典動態規劃問題總結

2021-08-06 06:56:00 字數 3045 閱讀 5282

動態規劃引入

首先我們以乙個最基本的例子來分析——菲波那切數列。

我們都知道,菲波那切數列的遞推公式f(n) = f(n-1)+f(n-2) (這裡我就說明一般情況,不列舉邊界條件了),很簡單,如果我們用遞迴的方法來求解f(n),兩三行**就出來了。那麼我們深入分析一下這樣有什麼問題?

f(2) = f(1) + f(0);

f(3) = f(2) + f(1);

f(4) = f(3) + f(2);

f(5) = f(4) + f(3);

......

計算乙個f(5)我們需要計算乙個f(4)和乙個f(3),而乙個f(4)又需要乙個f(3)和乙個f(2),這其中就有了乙個重複的f(3),那麼在繼續往下推導,會發現有越來越多的重複。當我們在計算機中計算f(40)並輸出時,我們會發現已經有相當長時間的延時了,為什麼?因為這樣的遞迴重複計算太多了,導致整個演算法效率非常低。

由於上述過程存在著大量的重複計算,我們可以用乙個陣列儲存所有已經計算過的項,這樣便可以達到用空間換時間的目的,在這種情況下,時間複雜度為o(n),而空間複雜度也為o(n)。事實上,我們所述的這種演算法就是利用了動態規劃的思想。

動態規劃演算法的思想與分治法類似,也是通過組合子問題的解而解決整個問題。其基本思路是利用乙個表來記錄所有已解的子問題的答案,不管該子問題以後是否被用到,只要它被計算過,就將結果填入表中,這樣就可以避免重複計算問題。

動態規劃演算法的設計可以分為如下幾個步驟:

1)描述最優解的結構;

2)遞迴定義最優解的值;

3)按自底向上的方式計算最優解的值;

4)由計算出的結果構造乙個最優解;

其中第1~3步構成問題的動態規劃解的基礎。

適合動態規劃方法的最優化問題的兩個要素:最優子結構,重疊子問題

例1:求用1*2的瓷磚覆蓋2*m的地板有幾種方式?

分析:假設所求問題的解為f(m),有下面兩種情況:

當第一塊瓷磚豎著放的時候,問題轉換成求用1*2的瓷磚覆蓋剩下的2*(m-1)的方式,即f(m-1)。

當第一塊瓷磚橫著放的時候,則必有另一塊瓷磚橫著放在其下面,問題轉換成求用1*2的瓷磚覆蓋 剩下的2*(m-2)的方式,即f(m-2)。

在求f(m-1)和f(m-2)時,由於第一列地板的覆蓋方式已經不同,故f(m-1)種覆蓋方式和f(m-2)中覆蓋方式沒有重疊,故:

f(m) = f(m-1)+f(m-2)

其中,f(1) = 1,f(2) = 2。可見我們能夠將問題規模縮小。

仔細看遞推式,其實就和菲波那切數列是一樣的,既然這樣,我們就不要用上面的遞迴方式進行求解f(m)了,而是用動態規劃的方式,建立乙個**,儲存每一步驟的f(i).

//...

int a[100];

int func(int m){}

a[1] = 1;

a[2] = 2;

for(int i = 3; i <= m; ++i)

a[i] = a[i-1] + a[i-2];

return a[m];

}//...

例2:lcs(最長公共子串行問題)

注:lcs問題不要求所求得的字元在所給的字串中是連續的。

分析:假設x=和y=的乙個最長公共子串行為z=,

1)若x(m) = y(n),則必然有z(k) = x(m) = y(n),且z(k-1)是x(m-1)和y(n-1)的最長公共子串行;

2)若x(m) != y(n)且z(k) != x(m),則z是x(m-1)和y的最長公共子串行;

3)若x(m) != y(n) 且z(k) != y(n),則z是x和y(n-1)的最長公共子串行;

也就是說,

當x(m) = y(n)時,lcs(x(m),y(n)) = lcs(x(m-1),y(n-1)) + 1;

當x(m) != y(n)時,lcs(x(m),y(n)) = max;

若用乙個二維**c來儲存lcs,則c[i][j]表示x和y長度分別為i和j時的lcs,顯然,當x或y為空時,lcs為0.

下面給出動態規劃演算法的**:

/* 動態規劃:最長公共子串行問題lcs */

const int inf = 99999;

int c[100][100];

int lcs_memo(string a, string b, int i, int j)

return c[i][j];

}int lcs_length(string a, string b)

下面再給出一種非遞迴的方法。

//dp[i][j]存放的是長度分別為i、j的字串a、b的lcs

int lcs(string a, string b, int m, int n)

} return dp[m][n];

}

例3: 01揹包問題:乙個揹包有一定的承重cap,有n件物品,每件都有自己的價值,記錄在陣列v中,也都有自己的重量,記錄在陣列w中,每件物品只能選擇要裝入揹包還是不裝入揹包,要求在不超過揹包承重的前提下,選出物品的總價值最大,給定物品的重量w價值v及物品數n和承重cap。請返回最大總價值。

分析:這裡以行n,列cap建立二維**dp[n+1][cap+1],其中dp[i][j]表示重量不超過j時的最大價值。那麼這裡就有兩種情況:

1)選擇第i件物品,則前i-1件物品的重量不能超過j-w[i];

2)不選擇第i件物品,則前i-1件物品的重量不能超過j;

即dp[i][j] = max(dp[i-1][j],dp[i-1][j-w[i]]+v[i]);

int getmaxvalue(vectorw, vectorv, int n, int cap)

}}

動態規劃經典問題總結

假設有幾種硬幣,如1 3 5,並且數量無限。請找出能夠組成某個數目的找零所使用最少的硬幣數。這是一道經典的動態規劃方法,我們可以維護乙個一維動態陣列dp,其中dp i 表示錢數為i時的最小硬幣數的找零,遞推式為 dp i min dp i dp i coins j 1 其中coins j 為第j個硬...

動態規劃經典問題

from 實現在 維基百科對動態規劃的定義 動態規劃 英語 dynamic programming,簡稱dp 是一種在數學 電腦科學和經濟學中使用的,通過把原問題分解為相對簡單的子問題的方式求解複雜問題的方法。動態規劃常常適用於有重疊子問題 1 和最優子結構性質的問題,動態規劃方法所耗時間往往遠少於...

動態規劃經典問題

子串 在給定的字串中選取連續的一段 子串行 可以不連續,但是要保證出現的順序與原字串相同 比如字串abcdefg abc既是子串又是子串行 acd只是子串行 一 最大連續子串行和 給定乙個整數序列a1,a2 an。求最大的連續的子串行的和。比如的最大連續子串行的和為5 3 1 1 2 萬能列舉?每次...