01 揹包問題

Hydrogen發表於2022-04-23

最近在複習演算法知識寫下這篇文章幫助自己理解記憶

01 揹包問題

01揹包問題的目標是在固定的容量限制內,達到最大的物品價值
01對含義:無法分割物品
01揹包問題通常有暴力回溯法和動態規劃兩種方式來解決

Brute Force

回溯法檢查所有組合 時間複雜度為指數級
很容易時間就爆表,這裡就不看了

動態規劃

動態規劃的核心在於尋找子問題,在這個題中我們首先去尋找子問題

尋找子問題

假設揹包最大重量為5
物品資訊如下

重量價值
物品147
物品235
物品356
物品433
物品528

dp表的每一個位置儲存的是這麼大的揹包,最大收益是多少
我們首先考慮,如果只有物品1, 如果裝不下,收益就是0
如果我們的揹包可以裝下,那麼最大收益就是7,我們更新第一行

012345
物品1000077
物品2
物品3
物品4
物品5

通過解決子問題獲得到全域性問題的解

現在考慮物品2,如果裝不下,收益就是上一行相同位置的結果

如果能裝下:判斷上一行相同位置的結果 此物品價值加上上一行去掉此物品重量後的重量最多能裝的價值
由此我們獲得狀態轉移方程

dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]]+values[i])
012345
物品100 (4 - weight of item 2)0077
物品20005max(7, (5 + 0))
物品3
物品4
物品5

不斷迭代

012345
物品1000077
物品2000577
物品3000577
物品4000577
物品50088813

最後結果為13

完整Python程式碼如下

#
# 程式碼中的類名、方法名、引數名已經指定,請勿修改,直接返回方法規定的值即可
#
# 計算01揹包問題的結果
# @param V int整型 揹包的體積
# @param n int整型 物品的個數
# @param vw int整型二維陣列 第一維度為n,第二維度為2的二維陣列,vw[i][0],vw[i][1]分別描述i+1個物品的vi,wi
# @return int整型
#
class Solution:
    def knapsack(self, V: int, n: int, vw: List[List[int]]) -> int:
        # write code here
        dp = [[0] * (V + 1) for _ in range(n)]
        for i in range(V + 1):
            if i >= vw[0][0]:
                dp[0][i] = vw[0][1]
        for i in range(1, n):
            for j in range(V + 1):
                if j < vw[i][0]:
                    dp[i][j] = dp[i-1][j]
                else:
                    dp[i][j] = max(dp[i-1][j], dp[i-1][j-vw[i][0]]+vw[i][1])
        return dp[n-1][V]

相關文章