01 揹包
題目
有N
件物品和一個容量爲V
的揹包。第i
件物品的費用是w[i]
,價值是v[i]
,求將哪些物品裝入揹包可使價值總和最大。
題解
- 定義數組
dp[i][j] # 代表前i個商品,放入一個容量爲j的揹包,所獲得的最大價值
- 初始化
# 如果要求恰好放滿揹包,則數組初始化爲 -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的情形)。
- 轉移方程
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]