01背包问题 二维dp
https://programmercarl.com/背包理论基础01背包-1.html
视频讲解:https://www.bilibili.com/video/BV1cg411g7Y6
有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
思考
dp[i][j] 表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
def test_2_wei_bag_problem1():weight = [1, 3, 4]value = [15, 20, 30]bagweight = 4# 二维数组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])print(dp[len(weight) - 1][bagweight])test_2_wei_bag_problem1()
01背包问题 一维dp
https://programmercarl.com/背包理论基础01背包-2.html
视频讲解:https://www.bilibili.com/video/BV1BU4y177kY
思考
在一维dp数组中,dp[j]表示:容量为j的背包,所背的物品价值可以最大为dp[j]。
思考
使用滚动数组,先物品再背包。背包遍历需要逆序,正序的话上一层的左侧值就被覆盖了,无法滚动。
def test_1_wei_bag_problem():weight = [1, 3, 4]value = [15, 20, 30]bagWeight = 4# 初始化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])print(dp[bagWeight])
416. 分割等和子集
本题是 01背包的应用类题目
https://programmercarl.com/0416.分割等和子集.html
视频讲解:https://www.bilibili.com/video/BV1rt4y1N7jE
思考
暴力回溯太费事了。
转换为01背包问题。背包容量为sum/2,物品重量为nums[i],价值也是nums[i]
dp[i] 背包容量i是否可以装满
class Solution:def canPartition(self, nums: List[int]) -> bool:if len(nums)==1:return Falsesum_ = sum(nums)if sum_ % 2 !=0:return Falsek = int(sum_ / 2)# dp[i] 背包容量i是否可以装满dp = [False] * (k+1)dp[0] = Truefor num in nums:for i in range(k,0,-1):if i>=num:dp[i] = dp[i] or dp[i-num]return dp[k]