01背包问题定义:有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
暴力解法:回溯法,枚举所有情况,每个物品是取与不取两个状态
二维数组方法
m,n = map(int, input().split())
weight = list(map(int, input().split()))
value = list(map(int, input().split()))
# print(m,n)
dp = [[0]*(n+1) for _ in range(m)]
# 初始化,dp[i][0]本身就都是0了,只需要初始dp[0][i]
for i in range(n+1):
if i >= weight[0]:
dp[0][i] = value[0]
# print(dp)
for i in range(1, m): #遍历物品
for j in range(1, n+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])
# print(dp)
max_value = dp[m-1][n]
print(max_value)
一维数组方法:核心想法,当前层i都是由上一层的i-1推导出来的,我们可以把上一层的拷贝到当前层进行计算,然后再用当前层的新计算值覆盖i+1层
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = bagWeight; j >= weight[i]; j--) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
}
题目:卡码网46:46. 携带研究材料(第六期模拟笔试) (kamacoder.com)
m,n = map(int, input().split())
weight = list(map(int, input().split()))
value = list(map(int, input().split()))
# print(m,n)
dp = [0]*(n+1)
# 初始化,dp[i]本身就都是0了
for i in range(m): #遍历物品
for j in range(n, weight[i]-1, -1): #遍历空间
#注意这里因为是倒叙,所以是从n开始!不是n+1
# print(i,j, weight[i])
dp[j] = max(dp[j], dp[j-weight[i]]+value[i])
# pass
# print(dp)
max_value = dp[n]
print(max_value)
leetcode题目链接:416. 分割等和子集 - 力扣(LeetCode)
题意:给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
示例 1:
思路:只要找到集合里能够出现 sum / 2 的子集总和,就算是可以分割成两个相同元素和子集了。因为每个元素只能使用1次,所以是0-1背包问题
只有确定了如下四点,才能把01背包问题套到本题上来。
class Solution:
def canPartition(self, nums: List[int]) -> bool:
n = len(nums)
target = sum(nums)//2
dp = [0]*(target+1)
if sum(nums)%2 != 0:
return False
for i in range(n):
# print(dp)
for j in range(target, nums[i]-1, -1):
dp[j] = max(dp[j], dp[j-nums[i]]+nums[i])
# print(dp)
if dp[target] == target:
return True
else:
return False