leetcode的揹包問題

01 揹包

題目

N件物品和一個容量爲V的揹包。第i件物品的費用是w[i],價值是v[i],求將哪些物品裝入揹包可使價值總和最大。

題解

  1. 定義數組
dp[i][j] # 代表前i個商品,放入一個容量爲j的揹包,所獲得的最大價值
  1. 初始化
# 如果要求恰好放滿揹包,則數組初始化爲 -inf
dp = [[-inf] * (amount + 1) for _ in range(n)]
# 如果要求恰好放滿揹包,則數組初始化爲 0
dp = [[0] * (amount + 1) for _ in range(n)]

需要格外強調的是:第一、無論初始化是如何進行的,但是我們每次迭代商品的時候:dp[i][0]一定要等於0,因爲放滿容量爲0的揹包,價值肯定是0。第二、動態數組的長度是(容量+1)(要考慮容量爲0的情形)。

  1. 轉移方程
for i in range(n+1): # 初始化工作對i==0的時候已經做了處理,所以這裏可以不用再考慮。
	for j in range(w[i],v+1): # 正序
		f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])

01 揹包簡化

我們觀察轉移方程:

f[i][j]=max(f[i−1][j],f[i−1][j−w[i]]+v[i])

發現f[i][j]只和上一行正上方上一行的左上方有關。如果我們只用一行數據正序遍歷的話,我們會將上一行左上方的數據先覆蓋掉。所以我們採用逆序遍歷。

def package_01(size, values, weights):
    # dp[j]代表裝滿容量爲j的揹包能產生的最大價值

    import numpy
    # 如果不要求完全裝滿
    dp = numpy.array([0] * (size + 1))
    # 如果要求完全裝滿
    # dp = [-float("inf")] * (size + 1)

    # 初始化,無論是要求裝滿還是不裝滿,初始化規則一樣,只是如果要求不裝滿,已經是0,可以省略初始化條件
    dp[0] = 0

    for i in range(len(values)):
        for j in range(size, weights[i] - 1, -1): # 逆序
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i])

    return dp[size]

完全揹包

題目

N種商品和一個容量爲V的揹包。第i件物品有無數件,且費用是w[i],價值是v[i],求將哪些物品裝入揹包可使價值總和最大。

題解

完全揹包和01揹包的邏輯基本類似,但是由於物品可以任意次取,所以我們每個物品取用多少次 取決於當 0<=k*w[i]<=j時,f[i−1][j−k*w[i]]+k*v[i]最大。

f[i][j]=max(f[i−1][j−k*w[i]]+k*v[i]) 0<=k*w[i]<=j

將上面的邏輯轉爲程序語言

k = 1
while k * weights[i] <= j:
    dp[i][j] = max(dp[i][j], dp[i - 1][j - k * weights[i]] + k * weights[i])
    k += 1

最終解法:

def package_total(size, values, weights):
    import numpy
    # 如果不要求完全裝滿
    dp = numpy.array([[0] * (size + 1) for _ in range(len(values))])

    # 初始化,無論是要求裝滿還是不裝滿,初始化規則一樣,只是如果要求不裝滿,已經是0,可以省略初始化條件
    dp[0][0] = 0

    for i in range(len(values)):
        for j in range(weights[i], size + 1):
            k = 1
            while k * weights[i] <= j:
                dp[i][j] = max(dp[i][j], dp[i - 1][j - k * weights[i]] + k * weights[i])
                k += 1

    return dp[-1][-1]

完全揹包簡化

def package_total(size, values, weights):
    # dp[j]代表裝滿容量爲j的揹包能產生的最大價值

    import numpy
    # 如果不要求完全裝滿
    dp = numpy.array([0] * (size + 1))

    # 如果要求完全裝滿
    # dp = [-float("inf")] * (size + 1)

    # 初始化,無論是要求裝滿還是不裝滿,初始化規則一樣,只是如果要求不裝滿,已經是0,可以省略初始化條件
    dp[0] = 0

    for i in range(len(values)):
        for j in range(weights[i], size + 1): # 正序
            dp[j] = max(dp[j], dp[j - weights[i]] + values[i])

    return dp[size]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章