bool canPartition(vector<int>& nums)
{
int n = nums.size();
if(n < 2) return false;
int sum = accumulate(nums.begin(), nums.end(), 0);
int maxNum = *max_element(nums.begin(), nums.end());
if(sum & 1) return false;
int target = sum / 2;
if(maxNum > target) return false;
// 建立背包
vector<vector<int>> dp(n, vector<int>(target + 1, 0));
// 初始化
for(int i = 0; i < n; ++ i) dp[i][0] = 0;
for(int j = nums[0]; j <= target; ++ j) dp[0][j] = nums[0];
for(int i = 1; i < n; ++ i)
{
for(int j = 1; j <= target; ++ j)
{
if(j < nums[i]) //如果新增的一个物品质量超过背包容量
{
dp[i][j] = dp[i - 1][j]; //物品不放进背包,能装进背包的最大质量是新增物品之前的质量
}else{ // 如果没有超过
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
}
}
}
return dp[n - 1][target] == sum / 2;
}
// dp[i][j] = 有i个物品,分成两个相等的子集,最大重量是多少
// dp[i][0] = 0 有i个物品,分成两个相等中、重量为0的子集,最大质量就是0
// dp[0][j] = nums[0] 没有什么实际意义但是在求dp[i][j]的时候会用到。
样例输入
4
1 2 3 1
样例输出
3
数据规模
n<=15
#include<bits/stdc++.h>
using namespace std;
//判断是否能分割成两个相等子序列,存在则返回sum/2 ,否则返回 0
int getPartitionValue(vector<int> nums)
{
int n = nums.size();
if(n < 2) return 0; // 如果只有一个木棍 返回 0
int sum = accumulate(nums.begin(), nums.end(), 0); // 计算所有木棍的总长
int maxNum = *max_element(nums.begin(), nums.end()); // 找到最长木棍的第一个位置
int target = sum / 2;
if(maxNum > target) return 0;
//建立背包
vector<vector<int> > dp(n, vector<int>(target + 1, 0));
// 相当于一个二维int数组,dp[n][target + 1] ,并且初始化所有值为 0
//初始化背包
for(int i = 0; i < n; ++ i) dp[i][0] = 0;
for(int j = nums[0]; j <= sum / 2; ++ j) dp[0][j] = nums[0];
for(int i = 1; i < n; ++ i)
{
for(int j = 1; j <= target; ++ j)
{
if(j < nums[i])
{
dp[i][j] = dp[i - 1][j];
} else{
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - nums[i]] + nums[i]);
}
}
}
return dp[n - 1][target] == sum / 2 ? sum /2 : 0;
}
int main()
{
int n;
cin >> n; //n个棍子
vector<int> nums(n);
for(int i = 0; i < n; ++ i)
cin >> nums[i]; //棍子长度
sort(nums.begin(), nums.end()); //对棍子长度排序
int sum = accumulate(nums.begin(), nums.end(), 0); //计算棍子总长
int i = 0;
int ans = 0;
//在不删除棍子情况下,sum如果为偶数,判断是否能分割成两个相等子序列,并保存结果
if(sum % 2 == 0) ans = getPartitionValue(nums);
//如果每次总和是偶数,都去判断是否存在可分成使得两个子集的元素和相等,如果存在返回值
while(i < nums.size())
{
sum = accumulate(nums.begin(), nums.end(), 0);
if((sum - nums[i]) % 2 == 0)
{
nums.erase(nums.begin() + i);
ans = max(getPartitionValue(nums), ans);
i = 0;
continue;
}
++ i;
}
cout << ans << endl;
return 0;
}
参考文章