目录
🎈背包问题理论基础
👜01背包
✨二维dp数组01背包
✨一维dp数组01背包(滚动数组)
🎈LeetCode416.分割等和子集
🎈背包问题理论基础
👜01背包
有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。
每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况,那么时间复杂度就是O(2^n),这里的n表示物品数量。
✨二维dp数组01背包
假设背包的最大容量为4,有3件物品
物品 重量 价值 0 1 15 1 3 20 2 4 30 动规五部曲:
1.确定dp数组的含义
dp[i][j]表示从下标为[0-i]的物品里任意取,放进容量为j的背包,价值总和最大是多少。
2.确定递推公式
- 不放物品i:dp[i][j]=dp[i-1][j]
- 放物品i:dp[i][j]=dp[i-1][j-weight[i]]+value[i]
dp[i][j]=Math.max( dp[i-1][j],dp[i-1][j-weight[i]]+value[i])
3.初始化
dp[0][j]=放物品0的时候的最大价值
4.遍历
先遍历背包或者先遍历物品都可以
✨一维dp数组01背包(滚动数组)
假设背包的最大容量为4,有3件物品
物品 重量 价值 0 1 15 1 3 20 2 4 30 动规五部曲:
1.确定dp数组的含义
dp[j]表示背包容量为j时,价值总和最大是多少。
2.确定递推公式
- 不放物品i:dp[j]=dp[j]
- 放物品i:dp[j]=dp[j-weight[i]]+value[i]
dp[i][j]=Math.max( dp[j],dp[j-weight[i]]+value[i])
3.初始化
dp[0]=0
4.遍历
先遍历物品再遍历背包,不能先遍历背包再遍历物品
除了01背包还有完全背包、多重背包、分组背包和混合背包等等
🎈LeetCode416.分割等和子集
416.分割等和子集
给你一个 只包含正整数 的 非空 数组
nums
。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
public boolean canPartition(int[] nums) {
int sum=0;
for(int i=0;i<nums.length;i++){
sum+=nums[i];
}
if(sum%2==1){
return false;
}
int value=sum/2; //目标价值
// dp[j]表示背包容量为j时获得的最大价值
int[] dp=new int[10001];
// dp[j]=Math.max(dp[j],dp[j-nums[i]]+nums[i])
// nums中的元素既是重量也是价值、最后判断dp[value]==value
// 初始化
dp[0]=0;
for(int i=0;i<nums.length;i++){
for(int j=value;j>=nums[i];j--){
dp[j]=Math.max(dp[j],dp[j-nums[i]]+nums[i]);
if(dp[j]==value){
return true;
}
}
}
return dp[value]==value;
}