背包问题:
1. 0-1背包:n种物品,每种物品只有一个
2. 完全背包:n种物品,每种物品有无穷多个
3. 多重背包:n种物品,每种物品的个数各不相同
背包问题:每个物品都有自己的重量和价值,最多只能放的重量为m,最多的价值为多少
① 二维dp数组解法:
1. dp数组的含义
dp[i][j]: 下标为0到i的物品任取放进容量为j的背包里的最大价值
如果不放第i个物品 价值为dp[i - 1][j]
放物品i的价值 dp[i - 1][j - weight[i]] + value[i] (当前物品的价值加上剩余空间的最大价值)
2. 递推公式
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])
3. 初始化
第一列初始化为0,因为背包容量为0的情况,最大价值就是0
第一行初始化根据物品0的重量和价值来,如果背包重量大于等于物品0 的重量的元素,初始化为物品0的重量,小于的话初始化成0.
其他位置不需要初始化,或者初始化成任意值
4. 遍历顺序
对于二维dp数组求解0-1背包问题的遍历顺序都可以。
def test_2_wei_bag_problem1(weight, value, bagweight):
# 二维数组
dp = [[0] * (bagweight + 1) for _ in range(len(weight))]
# 初始化
for j in range(weight[0], bagweight + 1):
dp[0][j] = value[0]
# weight数组的大小就是物品个数
for i in range(1, len(weight)): # 遍历物品
for j in range(bagweight + 1): # 遍历背包容量
if j < weight[i]:
dp[i][j] = dp[i - 1][j]
else:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])
return dp[len(weight) - 1][bagweight]
if __name__ == "__main__":
weight = [1, 3, 4]
value = [15, 20, 30]
bagweight = 4
result = test_2_wei_bag_problem1(weight, value, bagweight)
print(result)
② 一维dp数组解法
上一层拷贝到当前层,然后直接从当前层计算。每次计算都更新本行数据(滚动数组)
1. dp数组的含义
dp[j] 容量j的背包能装的最大价值
2. 递推公式
dp[j] = max(dp[j],dp[j - weight[i]] + value[i])
3. 初始化
因为取最大值,所以都初始化成0就行了
4. 遍历顺序
因为每次重复利用,所以需要倒序遍历,否则会重复计算。
只能先遍历物品 再遍历背包
def test_1_wei_bag_problem(weight, value, bagWeight):
# 初始化
dp = [0] * (bagWeight + 1)
for i in range(len(weight)): # 遍历物品
for j in range(bagWeight, weight[i] - 1, -1): # 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
return dp[bagWeight]
if __name__ == "__main__":
weight = [1, 3, 4]
value = [15, 20, 30]
bagweight = 4
result = test_1_wei_bag_problem(weight, value, bagweight)
print(result)
class Solution:
def canPartition(self, nums: List[int]) -> bool:
val = sum(nums) / 2
if val != int(val):
return False
else:
val = int(val)
# len(nums)个数中任取,能不能把容量为val的背包装满 dp[val] = val
dp = [0] * (val + 1)
for i in nums: #遍历物品,物品的重量为i,价值也为i
for j in range(val, i - 1, -1): #一维dp数组,反向遍历背包,遍历到物品的重量i为止
dp[j] = max(dp[j], dp[j - i] + i)
return dp[val] == val #判断容量为val的背包,装满的最大价值是不是等于val
转化为0-1背包问题:
背包容量为sum(nums)/2
物品的重量和质量都是nums[i]
容量为sum(nums)/2的背包能装的最大价值是否等于sum(nums)/2