主要 学习了一下01背包的问题 二维dp数组和一维dp数组的处理 然后是01背包的应用类题目
将这个数组分割成两个子集,使得两个子集的元素和相等。那肯定是对半分,把vector里的元素求和取半就行了。求和用库函数也可以做,第三个参数是初始值
int sum = accumulate(nums.begin(), nums.end(), 0);
这道题用01背包来做确实比较难想。
- 背包的体积为sum / 2
- 背包要放入的商品(集合里的元素)重量为 元素的数值,价值也为元素的数值
- 背包如果正好装满,说明找到了总和为 sum / 2 的子集。
- 背包中每一个元素是不可重复放入。
01背包是找到固定大小容量背包里价值最大的 而这个题目只要在找价值最大的时候也就是价值在递增的时候会不会出现dp[sum / 2] == sum / 2 的情况 具体代码如下:
class Solution {
public:
bool canPartition(vector<int>& nums) {
int sum = 0;
// dp[i]中的i表示背包内总和
// 题目中说:每个数组中的元素不会超过 100,数组的大小不会超过 200
// 总和不会大于20000,背包最大只需要其中一半,所以10001大小就可以了
vector<int> dp(10001, 0);
for (int i = 0; i < nums.size(); i++) {
sum += nums[i];
}
// 也可以使用库函数一步求和
// int sum = accumulate(nums.begin(), nums.end(), 0);
if (sum % 2 == 1) return false;
int target = sum / 2;
// 开始 01背包
for(int i = 0; i < nums.size(); i++) {
for(int j = target; j >= nums[i]; j--) { // 每一个元素一定是不可重复放入,所以从大到小遍历
dp[j] = max(dp[j], dp[j - nums[i]] + nums[i]);
}
}
// 集合中的元素正好可以凑成总和target
if (dp[target] == target) return true;
return false;
}
};