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]