【题目描述】
给定一个只包含正整数的非空数组,是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
注:每个元素中的元素不会超过100,数组大小不会超过200。
【示例】
示例1:输入[1,2,6,3] 输出true,数组可以分为[1,2,3] 和[6];
示例2:输入[1,2,3,5] 输出false,数组不能分割成两个元素和相等的子集。
【分析】
看数组是否能分成两个子集使得两个子集的元素和相等,则需要找到集合里能够出现sum/2的子集总和的元素。
因为数组中的每个元素都只能取一次,故利用0-1背包进行解决。背包问题:有N件物品和一个最多能被重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次,求解将哪些物品装入背包里物品价值总和最大。故
- sum/2看成背包的最大容量;
bagweight = sum/2;
- 把元素当作物品,物品的重量和价值都为元素的值;
weight[i] = value[i] = arr[i];
- 假若背包最大容量的值等于sum/2即可认为该数组可以分为两个元素和相等的子集。
f[bagweight] = sum/2;
【动态规划步骤分析】
- (1)确定状态
f[j]
:j代表背包容量,f[j]
表示最大的子集总和。
- (2)转移方程
f[j] = max(f[j],f[j-arr[i]]+arr[i])
- (3)初始化
f[0] = 0;
- (4)计算顺序
- 使用一维数组,先遍历物品,再遍历背包,且内层循环倒序遍历。
【C++实现】
时间复杂度:O(N^2)
空间复杂度:O(N)
#include <iostream>
#include <vector>
using namespace std;
bool ArrCanPartition(vector<int>