Y 分鐘速成 Dynamic Programming

小X學技術發表於2022-11-23

原始碼下載: dynamic-programming-cn.html.markdown

動態規劃

簡介

動態規劃是一種實用的技巧,它可以用來解決一系列特定問題。它的思路很簡單,如果你對某個給定的輸入解決了一個問題,那麼你可以儲存已有資訊,以避免重複計算,節約計算時間。

記住,如果忘記歷史,就要被迫做更多的苦力。斐波那契數列就是一個顯然的例子。

解決問題的方式

  1. 自頂向下 : 利用分支策略分解問題。如果你已經解決過當前子問題了,那麼就返回已有資訊。如果當前子問題沒有計算過,那麼就對它進行計算。這樣的方法很易於思考、很直觀。這被稱作“記憶化”。
  2. 自底向上 : 首先分析問題,將問題分解為不同規模的問題,並決定它們的順序,按順序計算,直到解決給定規模的問題。這樣的流程可以保證在解決較大的問題之前解決(它所依賴的)較小的問題。這種流程被稱作“動態規劃”。

動態規劃的例子最長上升子序列問題。給定S= {a[1] , a[2] , a[3], a[4], ............., a[n-1], a[n] },求出一個子序列,使得對於所有在這個子序列中所有滿足j<i的j與i,滿足aj<ai。首先我們要討論以原序列的第i個元素結尾的最長上升子序列dp[i]。那麼答案是整個dp序列的最大值。考慮dp[i],它的最後一個元素為a[i]。列舉它的倒數第二個元素a[j],則a[j]<a[i]成立。則dp[i]就是所有這樣的dp[j]的最大值加上1(最後一個元素)。這個演算法具有O(n^2)的時間複雜度。

此演算法的虛擬碼:

for i=0 to n-1
    dp[i]=0
    for j=0 to i-1
        if (a[i] >  a[j] and dp[i]<dp[j])
            LS[i] = LS[j]
    dp[i]=dp[i]+1
for i=0 to n-1
    if (largest < dp[i])
        largest = dp[i]

這個演算法的複雜度可以透過將陣列換為其他資料結構來最佳化,來獲得O(n * log n)的時間複雜度。

同樣的思路可以求出有向無環圖上的最大路徑。

一些著名的動態規劃問題及其實現

Floyd Warshall 演算法 - 教程與C實現原始碼
整數揹包問題 - 教程與C實現原始碼
最長公共子序列問題 - 教程與C實現原始碼

線上資源

有建議?或者發現什麼錯誤?在Github上開一個issue,或者發起pull request

原文由Akashdeep Goel編寫,並由0個好心人修改。
Translated by: EtaoinWu
© 2022 Akashdeep Goel
本作品採用 CC BY-SA 3.0 協議進行許可。

相關文章