動態規劃套路秒殺揹包問題

2021-10-07 12:09:26 字數 2464 閱讀 3661

給你乙個可裝載重量為w的揹包和n個物品,每個物品有重量和價值兩個屬性。其中第i個物品的重量為wt[i],價值為val[i],現在讓你用這個揹包裝物品,最多能裝的價值是多少?

舉個簡單的例子,輸入如下:

n = 3, w = 4

wt = [2, 1, 3]

val = [4, 2, 3]

演算法返回 6,選擇前兩件物品裝進揹包,總重量 3 小於w,可以獲得最大價值 6。

題目就是這麼簡單,乙個典型的動態規劃問題。這個題目中的物品不可以分割,要麼裝進包裡,要麼不裝,不能說切成兩塊裝一半。這也許就是 0-1 揹包這個名詞的來歷。

解決這個問題沒有什麼排序之類巧妙的方法,只能窮舉所有可能.

動規標準套路

第一步要明確兩點,「狀態」和「選擇」。

先說狀態,如何才能描述乙個問題局面?只要給定幾個可選物品和乙個揹包的容量限制,就形成了乙個揹包問題,所以狀態有兩個,就是「揹包的容量」和「可選擇的物品」。

再說選擇,對於每件物品,你能選擇什麼?選擇就是「裝進揹包」或者「不裝進揹包」。

明白了狀態和選擇,動態規劃問題基本上就解決了,只要往這個框架套就完事兒了:

for 狀態1 in 狀態1的所有取值:

for 狀態2 in 狀態2的所有取值:

for ...

dp[狀態1][狀態2][...] = 擇優(選擇1,選擇2...)

第二步要明確dp陣列的定義。

dp陣列是什麼?其實就是描述問題局面的乙個陣列。換句話說,我們剛才明確問題有什麼「狀態」,現在需要用dp陣列把狀態表示出來。

首先看看剛才找到的「狀態」,有兩個,也就是說我們需要乙個二維dp陣列,一維表示可選擇的物品,一維表示揹包的容量。

dp[i][w]的定義如下:對於前i個物品,當前揹包的容量為w,這種情況下可以裝的最大價值是dp[i][w]。

比如說,如果 dp[3][5] = 6,其含義為:對於給定的一系列物品中,若只對前 3 個物品進行選擇,當揹包容量為 5 時,最多可以裝下的價值為 6。

ps:為什麼要這麼定義?便於狀態轉移,或者說這就是套路,記下來就行了。

根據這個定義,我們想求的最終答案就是dp[n][w]。base case 就是dp[0][…] = dp[…][0] = 0,因為沒有物品或者揹包沒有空間的時候,能裝的最大價值就是 0。

細化上面的框架:

int dp[n+1][w+1]

dp[0][..] = 0

dp[..][0] = 0

for i in [1..n]:

for w in [1..w]:

dp[i][w] = max(

把物品 i 裝進揹包,

不把物品 i 裝進揹包

)return dp[n][w]

第三步,根據「選擇」,思考狀態轉移的邏輯。

簡單說就是,上面偽碼中「把物品i裝進揹包」和「不把物品i裝進揹包」怎麼用**體現出來呢?

這一步要結合對dp陣列的定義和我們的演算法邏輯來分析:

先重申一下剛才我們的dp陣列的定義:

dp[i][w]表示:對於前i個物品,當前揹包的容量為w時,這種情況下可以裝下的最大價值是dp[i][w]。

如果你沒有把這第i個物品裝入揹包,那麼很顯然,最大價值dp[i][w]應該等於dp[i-1][w]。你不裝嘛,那就繼承之前的結果。

如果你把這第i個物品裝入了揹包,那麼dp[i][w]應該等於dp[i-1][w-wt[i-1]] + val[i-1]。

首先,由於i是從 1 開始的,所以對val和wt的取值是i-1。

而dp[i-1][w-wt[i-1]]也很好理解:你如果想裝第i個物品,你怎麼計算這時候的最大價值?換句話說,在裝第i個物品的前提下,揹包能裝的最大價值是多少?

顯然,你應該尋求剩餘重量w-wt[i-1]限制下能裝的最大價值,加上第i個物品的價值val[i-1],這就是裝第i個物品的前提下,揹包可以裝的最大價值。

綜上就是兩種選擇,我們都已經分析完畢,也就是寫出來了狀態轉移方程,可以進一步細化**:

for i in [1..n]:

for w in [1..w]:

dp[i][w] = max(

dp[i-1][w],

dp[i-1][w - wt[i-1]] + val[i-1]

)return dp[n][w]

最後一步,把偽碼翻譯成**,處理一些邊界情況。

我用 c++ 寫的**,把上面的思路完全翻譯了一遍,並且處理了w - wt[i-1]可能小於 0 導致陣列索引越界的問題:

int knapsack(int w, int n, vector& wt, vector& val)  else }}

return dp[n][w];

}

參考:

動態規劃 揹包問題

給定n個物品,重量是,價值是,包的容量 承重 是w 問,放入哪些物品能使得包內價值最大 1 需要將問題轉化為子問題,通過遞迴實現,且子問題必然與父問題存在關聯 2 定義v i,j 表示為,當item取自前i個items且揹包capacity j 時,揹包問題的最優解,也即最高的價值。3 從前i個it...

動態規劃 揹包問題

不廢話,直接上 動態規劃,揹包問題。輸入為 int n 物品的種類數。int n weight 各件物品的重量。int n value 各種物品的價值。int w 揹包最大的裝載重量。輸出 v n b 的值,最大的裝載價值。x n 各類物品的裝載數量。author huangyongye publi...

動態規劃 揹包問題

1 開心的金明 問題描述 金明今天很開心,家裡購置的新房就要領鑰匙了,新房裡有一間他自己專用的很寬敞的房間。更讓他高興的是,媽媽昨天對他說 你的房間需要購買哪些物品,怎麼布置,你說了算,只要不超過n 元錢就行 今天一早金明就開始做預算,但是他想買的東西太多了,肯定會超過媽媽限定的n 元。於是,他把每...