動態規劃
動態規劃(英語:Dynamic programming,簡稱DP)是一種在數學、管理科學、電腦科學、經濟學和生物資訊學中使用的,通過把原問題分解為相對簡單的子問題的方式求解複雜問題的方法。
動態規劃常常適用於有重疊子問題[1]和最佳子結構性質的問題,動態規劃方法所耗時間往往遠少於樸素解法。
動態規劃背後的基本思想非常簡單。大致上,若要解一個給定問題,我們需要解其不同部分(即子問題),再根據子問題的解以得出原問題的解。
通常許多子問題非常相似,為此動態規劃法試圖僅僅解決每個子問題一次,從而減少計算量:一旦某個給定子問題的解已經算出,則將其記憶化儲存,以便下次需要同一個子問題解之時直接查表。這種做法在重複子問題的數目關於輸入的規模呈指數增長時特別有用。
概述
[編輯]動態規劃在尋找有很多重疊子問題的情況的最佳解時有效。它將問題重新組合成子問題。為了避免多次解決這些子問題,它們的結果都逐漸被計算並被儲存,從簡單的問題直到整個問題都被解決。因此,動態規劃儲存遞迴時的結果,因而不會在解決同樣的問題時花費不必要的時間。
動態規劃只能應用於有最佳子結構的問題。最佳子結構的意思是局部最佳解能決定全域最佳解(對有些問題這個要求並不能完全滿足,故有時需要引入一定的近似)。簡單地說,問題能夠分解成子問題來解決。
適用情況
[編輯]- 最佳子結構性質。如果問題的最佳解所包含的子問題的解也是最佳的,我們就稱該問題具有最佳子結構性質(即滿足最佳化原理)。最佳子結構性質為動態規劃演算法解決問題提供了重要線索。
- 無後效性。即子問題的解一旦確定,就不再改變,不受在這之後、包含它的更大的問題的求解決策影響。
- 子問題重疊性質。子問題重疊性質是指在用遞迴演算法自頂向下對問題進行求解時,每次產生的子問題並不總是新問題,有些子問題會被重複計算多次。動態規劃演算法正是利用了這種子問題的重疊性質,對每一個子問題只計算一次,然後將其計算結果儲存在一個表格中,當再次需要計算已經計算過的子問題時,只是在表格中簡單地檢視一下結果,從而獲得較高的效率,降低了時間複雜度。
實例
[編輯]包括但不限於切割鋼條問題、Floyd最短路問題、最大不下降子序列、矩陣鏈乘、凸多邊形三角剖分、背包問題、最長公共子序列、最佳二分搜尋樹等。
背包問題
[編輯]背包問題作為NP完全問題,暫時不存在多項式時間演算法。動態規劃屬於背包問題求解最佳解的可行方法之一。此外,求解背包問題最佳解還有搜尋法等,近似解還有貪婪法等,分數背包問題有最佳貪婪解等。 背包問題具有最佳子結構和重疊子問題。動態規劃一般用於求解背包問題中的整數背包問題(即每種物品所選的個數必須是整數)。 解整數背包問題: 設有件物品,每件價值記為,每件重量記為,用一個最大重量為的背包,求裝入物品的最大價值。 在總重量不超過W的前提下,我們希望總價格最高。對於,我們將在總重量不超過的前提下,總價格所能達到的最高值定義為。即為問題的答案。
顯然,A(Y)滿足:
其中,為第種物品的價格。
對於特例01背包問題(即每件物品最多放1件,否則不放入)的問題,我們將在總重量不超過Y的前提下,前j種物品的總價格所能達到的最高值定義為A(j, Y)。
A(j, Y)的遞推關係為:
- A(0, Y) = 0
- 如果wj > Y, A(j, Y) = A(j - 1, Y)
- 如果wj ≤ Y, A(j, Y) = max { A(j - 1, Y), pj + A(j - 1, Y - wj)}
參考Pascal代碼
for i:=1 to n do
for v:=totv downto v[i] do
f[v]:=max(f[v],f[v-v[i]]+p[i]);
writeln(f[totv]);
參考C++代碼(不含include和陣列聲明)
#define max(x,y) (x)>(y)?(x):(y) //max宏函数,也可以自己寫或者使用algorithm
for(int i=1;i<=n;i++)
for (v=totv;v>=v[i];v--)
f[v]=max(f[v],f[v-v[i]]+p[i]);
printf("%d",f[totv]); //或std::cout<<f[totv];
歷史
[編輯]術語「動態規劃」最初是在1940年代由理察·貝爾曼用來描述解決問題的過程,在這個過程中,人們需要一個接一個地找到最佳決策。到1953年,他將其精煉成為現代的含義,特別是指將較小的決策問題巢狀在較大的決策中,[2] 並且該領域隨後被電氣電子工程師學會認可為系統分析和工程學主題。貝爾曼的貢獻以貝爾曼方程的名義被銘記,它是動態規劃的核心結果,它以遞迴形式重申了最佳化問題。
貝爾曼選擇了「動態」這個詞來捕捉問題的隨時間變化的方面,也因為它聽起來令人印象深刻。[3] 「規劃」一詞指的是使用該方法來找到最佳的「程式」,在於軍事訓練或後勤計劃的意義。這種用法與短語「線性規劃」和「數學規劃」中的用法相同。[4]
術語起源的上述解釋是不足的。正如羅素和諾維格在他們的書中提到上述故事時所寫的那樣:「這不可能完全正確,因為他的第一篇使用這個詞(貝爾曼,1952)的論文出現在威爾遜於 1953 年成為國防部長之前。」[5]此外,還有Harold J. Kushner (頁面存檔備份,存於網際網路檔案館)在演講中的評論,他記得貝爾曼。他在談到貝爾曼時參照庫什納的話:「另一方面,當我問他同樣的問題時,他回答說他試圖通過加上動態來超越喬治·伯納德·丹齊格的線性規劃。也許這兩種動機都是正確的。」
使用動態規劃的演算法
[編輯]參考
[編輯]- ^ S. Dasgupta, C.H. Papadimitriou, and U.V. Vazirani, 'Algorithms', p 173, available at http://www.cs.berkeley.edu/~vazirani/algorithms.html (頁面存檔備份,存於網際網路檔案館)
- ^ Stuart Dreyfus. "Richard Bellman on the birth of Dynamical Programming".
- ^ Eddy, S. R. What is Dynamic Programming?. Nature Biotechnology. 2004, 22 (7): 909–910. PMID 15229554. S2CID 5352062. doi:10.1038/nbt0704-909.
- ^ Nocedal, J.; Wright, S. J. Numerical Optimization. Springer. 2006: 9. ISBN 9780387303031.
- ^ Russell, S.; Norvig, P. Artificial Intelligence: A Modern Approach 3rd. Prentice Hall. 2009. ISBN 978-0-13-207148-2.
- ^ Maximum_subarray_problem. [2023-01-18]. (原始內容存檔於2023-02-04).
- ^ Richard S. Sutton; Andrew G. Barto. Reinforcement Learning: An Introduction Second Edition. The MIT Press. 2018: 73 [2020-08-22]. (原始內容存檔於2022-01-18).