思路1:
dp[i][j]表示容量为j的背包装前i个物品的最大价值,从1开始。
n, bagweight = map(int, input().split())
weight = list(map(int, input().split()))
value = list(map(int, input().split()))
dp = [[0] * (bagweight + 1) for _ in range(n+1)]
for i in range(1, n+1):
for j in range(1, bagweight+1):
cur_w = weight[i-1]
if cur_w > j:
dp[i][j] = dp[i-1][j] # 容量不够;不加入当前物品,继承前i-1个物品的最大价值
else:
dp[i][j] = max(dp[i-1][j], # 不选择当前物品
dp[i-1][j-cur_w] + value[i-1]) # 选择当前物品
print(dp[n][bagweight])
思路2:
对于 0-1 背包问题,**滚动数组优化** 是最有效的优化方法,可以显著减少空间占用,并且在某些情况下可以提高运行速度。
n, bagweight = map(int, input().split())
weight = list(map(int, input().split()))
value = list(map(int, input().split()))
dp = [0] * (bagweight + 1)
for i in range(n):
cur_w = weight[i]
cur_v = value[i]
for j in range(bagweight, cur_w - 1, -1): # 从后往前遍历
dp[j] = max(dp[j], dp[j - cur_w] + cur_v)
print(dp[bagweight])
416. 分割等和子集
思路:
1 先判断是否和为偶数,否则false
2 转换为0-1背包问题,只要找到元素的子集和为sum//2,那剩下的元素和与前面的相同。
class Solution:
def canPartition(self, nums: List[int]) -> bool:
total = sum(nums)
# 必须是偶数
if total % 2 == 1:
return False
n = len(nums)
target = total // 2
# dp[i][j]表示容量为j的背包是否能装下 前i个数字(的子集,可以是空集,所以容量为0时候true)
dp = [[False] * (target+1) for _ in range(n+1)]
# 初始化 容量为0 true
for i in range(n+1):
dp[i][0] = True # 空集和为0
for i in range(1, n+1):
for j in range(1, target+1):
if nums[i-1] > j:
dp[i][j] = dp[i-1][j]
else:
dp[i][j] = dp[i-1][j] or dp[i-1][j-nums[i-1]] # 注意是bool
return dp[n][target]