1、题目描述
给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注意:
- 每个数组中的元素不会超过 100
- 数组的大小不会超过 200
2、示例
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].
3、题解
基本思想:动态规划,01背包问题,用递归回溯必超时,dp[i]表示能否填满容量为i的背包
01背包问题模板:
f[j]代表当前背包容量为j的时候,可以获取的最大价值。完全背包是从左向右遍历,f[j-V[i]]取到的是拿第i个物品时的值,是新值,可以重复无限的拿,f[j]的值也会随之增加。
V:商品的体积
W:商品的价值
//01背包
for (int i = 0; i < n; i++) {
for (int j = m; j >= V[i]; j--) {
f[j] = max(f[j], f[j-V[i]] + W[i]);
}
}
//完全背包
for (int i = 0; i < n; i++) {
for (int j = V[i]; j <= m; j++) {
f[j] = max(f[j], f[j-V[i]] + W[i]);
}
}
//dp[i]表示填充容量为i的方法个数
dp[0]=1;
for(auto num:nums)
{
for(int j=w;j>=num;j--)
{
dp[j]+=dp[j-num];
}
}
//dp[i]表示是否能填充容量为i
dp[0]=true;
for(auto num:nums)
{
for(int j=w;j>=num;j--)
{
dp[j]=dp[j]||dp[j-num];
}
}
#include<iostream>
#include<vector>
#include<algorithm>
#include<numeric>
using namespace std;
class Solution {
public:
bool canPartition(vector<int>& nums) {
//基本思想:动态规划,01背包问题,用递归回溯必超时
int sum=accumulate(nums.begin(),nums.end(),0);
if(sum&1) return false;
//dp[i]表示能否填满容量为i的背包
vector<bool> dp(sum/2+1,false);
dp[0]=true;
for(int i=0;i<nums.size();i++)
{
for(int j=sum/2;j>=nums[i];j--)
dp[j]=dp[j]||dp[j-nums[i]];
}
return dp[sum/2];
}
};
int main()
{
Solution solute;
vector<int> nums={1,2,3,4,6,7,8,9};
cout<<solute.canPartition(nums)<<endl;
return 0;
}