leetcode|LeetCode第 416 题(分割等和子集(C++))
416. 分割等和子集 - 力扣(LeetCode)
这是典型的子集背包问题:经典动态规划:子集背包问题 - labuladong的算法小抄
可以转化为0-1背包问题:
具体看注释
/*
转化为背包问题:
给定?个容量为 sum / 2 的背包和 N 个物品,每个物品的重量nums[i] 。
现在让你装物品,求问是否存在?种装法,恰好可以装满背包
*/
class Solution {
public:
bool canPartition(vector& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0);
//计算总和
if(sum % 2) return false;
//和为奇数时不可能划分为两个和相等的子集
sum /= 2;
int n = nums.size();
//dp[i][j]表示,对于前i个物品,当前背包容量为j时,如果dp[i][j] = 1,则说明可以刚好将背包装满
//也就是从数组的 [0, i] 这个子区间内挑选一些正整数,他们的和恰好为j
vector> dp(n+1, vector(sum+1));
for(int i = 0;
i <= n;
++i) dp[i][0] = 1;
//容量为0的时候(第一列)//对于物品的选择:可选(此时可以选可以不选),不可选(该物品重量大于剩余容量)
for(int i = 1;
i <= n;
++i){
for(int j = 1;
j <= sum;
++j){
//背包容量不足,无法装下第i个物品
if(nums[i-1] > j)dp[i][j] = dp[i-1][j];
//装入背包或者不装入背包
//什么时候dp[i][j] == 1呢?也就是前i个物品刚好可以装满j的重量,对应当前物品选或不选有两种情况:
//1、如果dp[i-1][j] == 1(前i-1个物品,恰好可以装满j的容量),那么此时不选择当前物品i的话
//dp[i][j] = dp[i-1][j] = 1,也就是前i个物品也可以刚好装满j的容量
//2、如果前i-1个物品,刚好可以装满j - nums[i-1]的容量,那么把当前物品装进去,就刚好能装满j的重量
//此时dp[i][j] = dp[i-1][j - nums[i-1]] = 1
//其他情况是dp[i][j] = 0,前i个物品没法做到刚好装满j的容量
elsedp[i][j] = dp[i-1][j - nums[i-1]] || dp[i-1][j];
}
}
return dp[n][sum];
}
};
【leetcode|LeetCode第 416 题(分割等和子集(C++))】状态压缩:
/*
转化为背包问题:
给定?个容量为 sum / 2 的背包和 N 个物品,每个物品的重量nums[i] 。
现在让你装物品,求问是否存在?种装法,恰好可以装满背包
*/
class Solution {
public:
bool canPartition(vector& nums) {
int sum = accumulate(nums.begin(), nums.end(), 0);
//计算总和
if(sum % 2) return false;
//和为奇数时不可能划分为两个和相等的子集
sum /= 2;
int n = nums.size();
vector dp(sum+1, 0);
dp[0] = 1;
//容量为0的时候(第一列)//对于物品的选择:可选(此时可以选可以不选),不可选(该物品重量大于剩余容量)
for(int i = 1;
i <= n;
++i){
for(int j = sum;
j >= 1;
--j){
if(nums[i-1] > j)dp[j] = dp[j];
elsedp[j] = dp[j - nums[i-1]] || dp[j];
}
}
return dp[sum];
}
};
推荐阅读
- 第6.2章(设置属性)
- 2018-02-06第三天|2018-02-06第三天 不能再了,反思到位就差改变
- 第三节|第三节 快乐和幸福(12)
- EffectiveObjective-C2.0|EffectiveObjective-C2.0 笔记 - 第二部分
- android第三方框架(五)ButterKnife
- 开学第一天(下)
- 野营记-第五章|野营记-第五章 讨伐梦魇兽
- 2018年11月19日|2018年11月19日 星期一 亲子日记第144篇
- 第326天
- 跌跌撞撞奔向你|跌跌撞撞奔向你 第四章(你补英语,我补物理)