1.确定dp数组含义,初始化
2.确定遍历顺序
3.确定dp公式
‘’‘’
0-1背包问题,可以分为二维dp和一维dp
有两种状态,当前物品放还是不放入背包
0-1背包,物品只能放一次,因此一维dp要考虑遍历顺序
‘’’
class solution:def bag2d(self,weight,value,bagweight):# dp[i][j]选0-i个物品,容量为j时候的价值dp=[[0]*(bagweight+1) for _ in range(len(value))]# 一般二维dp初始化都是遍历进行for j in range(weight[0],bagweight+1):dp[0][j]=value[0]for i in range(len(value)):for j in range(bagweight+1):# 遇到一个物品时,判断放还是不放if weight[i]>j: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)][bagweight-1]def bag1d(self,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]
分割等和子集问题
如果整体的元素总和都不可分,那肯定不可分
‘’’
背包的体积为sum / 2
背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
背包如果正好装满,说明找到了总和为 sum / 2 的子集。
背包中每一个元素是不可重复放入。
‘’’
class Solution:def canPartition(self, nums: List[int]) -> bool:_sum = 0# dp[i]中的i表示背包内总和# 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200# 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了dp = [0] * 10001for num in nums:_sum += num# 也可以使用内置函数一步求和# _sum = sum(nums)if _sum % 2 == 1:return Falsetarget = _sum // 2# 开始 0-1背包for num in nums:for j in range(target, num - 1, -1): # 每一个元素一定是不可重复放入,所以从大到小遍历dp[j] = max(dp[j], dp[j - num] + num)# 集合中的元素正好可以凑成总和targetif dp[target] == target:return True