C 演算法集錦(4) 給人看的動態規劃

2021-10-19 14:41:16 字數 2913 閱讀 6235

動態規劃問題,它不叫動態規劃演算法,因為它不是一種演算法,它是一眾型別的問題的統稱。

我們前面兩篇的「遞迴演算法」、「回溯演算法」,以及接下來會講的「貪心演算法」等都屬於動態規劃的範疇。

那麼,到底什麼是動態規劃呢?

在現實生活中,有一類活動的過程,由於它的特殊性,可將過程分成若干個互相聯絡的階段,在它的每一階段都需要作出決策,從而使整個過程達到最好的活動效果。因此各個階段決策的選取不能任意確定,它依賴於當前面臨的狀態,又影響以後的發展。當各個階段決策確定後,就組成乙個決策序列,因而也就確定了整個過程的一條活動路線.這種把乙個問題看作是乙個前後關聯具有鏈狀結構的多階段過程就稱為多階段決策過程,這種問題稱為多階段決策問題。在多階段決策問題中,各個階段採取的決策,一般來說是與時間有關的,決策依賴於當前狀態,又隨即引起狀態的轉移,乙個決策序列就是在變化的狀態中產生出來的,故有「動態」的含義,稱這種解決多階段決策最優化的過程為動態規劃方法 。

不扯那些彎彎繞的。

第一步:畫出暴力解法流程。

第二步:畫出決策樹(看著直觀)

第三步:寫出狀態轉移方程

第四步:決策樹剪枝

第五步:再優化:確定邊界

如果看了前面遞迴那篇的話,這裡就不難理解了。【c++】演算法集錦(2):遞迴精講

這五步列在這裡,並不是說每一步都要嚴格的執行,我們的目標是解決問題,解決動態規劃問題就需要狀態轉移方程,要寫出好的狀態轉移方程就需要決策樹以及決策樹的剪枝優化,要畫出決策樹,最好有個暴力解的流程圖。

不要看不起暴力求解,動態規劃問題最困難的就是寫出狀態轉移方程,即這個暴力解。優化方法無非是用備忘錄或者 dp table,再無奧妙可言。

看一下上面遞迴那篇,裡面的「爬樓梯」栗子。

先看下題目:給你 k 種⾯值的硬幣,⾯值分別為 c1, c2 … ck ,每種硬幣的數量無限,再給⼀個總金額 amount ,問你最少需要⼏枚硬幣湊出這個 金額,如果不可能湊出,演算法返回 -1 。

比方說 k=3,面值分別為:1,2,5。總金額:8。

那麼我們該如何來解決這個問題?

⾸先,這個問題是動態規劃問題,因為它具有「最優子結構」的。

那麼,既然知道了這是個動態規劃問題,就要思考如何列出正確的狀態轉移方程?

先確定「狀態」,也就是原問題和子問題中變化的變數。由於硬幣數量無限,所以唯⼀的狀態就是目標⾦額 amount 。

然後確定 dp 函式的定義:當前的⽬標⾦額是 n ,⾄少需要 dp(n) 個硬幣湊出該金額。

然後確定「選擇」並擇優,也就是對於每個狀態,可以做出什麼選擇改變當 前狀態。具體到這個問題,無論當的⽬標金額是多少,選擇就是從面額列表 coins 中選擇⼀個硬幣,然後目標金額就會減少:

寫出乙個暴力解法偽**:

def

dp(n)

:if n ==0:

return

0if n <0:

return-1

# 求最⼩值,所以初始化為正⽆窮

res =

float

('inf'

)for coin in coins:

subproblem = dp(n - coin)

# ⼦問題⽆解,跳過

if subproblem ==-1

:continue

res =

min(res,

1+ subproblem)

return res if res !=

float

('inf'

)else

-1

⾄此,狀態轉移⽅程其實已經完成了:

畫出遞迴樹看看:

下面點點點。

所以我們使用備忘錄來對決策樹進行剪枝操作(上面剪過了)

memo =

dict()

defdp

(n):

# 查備忘錄,避免重複計算

if n in memo:

return memo[n]

if n ==0:

return

0if n <0:

return-1

res =

float

('inf'

)for coin in coins:

subproblem = dp(n - coin)

if subproblem ==-1

:continue

res =

min(res,

1+ subproblem)

# 記⼊備忘錄

memo[n]

= res if res !=

float

('inf'

)else-1

return memo[n]

當然,我們也可以自底向上使用 dp table 來消除重疊子問題, dp 陣列的定義和剛才 dp 函式類似,定義也是⼀樣的: dp[i] = x 表示,當目標金額為 i 時,至少需要 x 枚硬幣。

【c++】演算法集錦(2):遞迴精講

【c++】演算法集錦(3):回溯,從入門到入土,七道試題精選、精講、精練

持續更新中。

演算法 4 動態規劃

最長公共子串行 0 1揹包問題 二叉搜尋樹 參考文獻 動態規劃 dynamic programming 是運籌學的乙個分支,是求解決策過程 decision process 最優化的數學方法。20世紀50年代初美國數學家r.e.bellman等人在研究多階段決策過程 multistep decisi...

演算法 4 動態規劃揹包

容量 m kg 的揹包,另外有 i個物品,重量分別為 w 1 w 2 w i kg 價值分別為 p 1 p 2 p i 元 將哪些物品放入揹包可以使得揹包的總價值最大?最大價值是多少?我們要求得 i個物體放入容量為 m kg 的揹包的最大價值 記為 c i m 在選擇物品的時候,對於每種物品 i只有...

演算法 動態規劃(4)最長公共子串 C

動態規劃 0 字串的交錯組成,二維表呈現的是,str1,str2 aim三個字串的關係,那麼本篇最長公共子串就是只是str1,str2兩個字串的關係。問題 給定兩個字串,返回兩個字串的最長公共子串。舉例 str1 1ab2345cd str2 12345ef 返回 2345 思路 dp 表示 把st...