我知道这在这里讨论了很多,但我正在努力解决这个问题。
我们有一组数字,例如 [3, 1, 1, 2, 2, 1],我们需要将其分成两个子集,因此每个和都相等或差异最小。
我看过wikipedia entry、 this page (problem 7) 和blog entry。
但是列出的每个算法都只给出 YES/NO 结果,我真的不明白如何使用它们来打印出两个子集(例如 S1 = {5, 4} 和 S2 = {5, 3, 3})。我在这里想念什么?
我知道这在这里讨论了很多,但我正在努力解决这个问题。
我们有一组数字,例如 [3, 1, 1, 2, 2, 1],我们需要将其分成两个子集,因此每个和都相等或差异最小。
我看过wikipedia entry、 this page (problem 7) 和blog entry。
但是列出的每个算法都只给出 YES/NO 结果,我真的不明白如何使用它们来打印出两个子集(例如 S1 = {5, 4} 和 S2 = {5, 3, 3})。我在这里想念什么?
伪多项式算法旨在为决策问题提供答案,而不是优化问题。但是,请注意,示例中布尔值表中的最后一行表示当前集合能够总计为 N/2。
在最后一行中,取布尔值所在的第一列true
。然后,您可以检查给定列中集合的实际值是多少。如果集合总和值为 N/2,则您已找到分区的第一组。否则,您必须检查哪个集合能够与 N/2 不同。您可以使用与上述相同的方法,这次是差异d。
这将是O(2^N)。这里没有使用动态规划。执行函数后可以打印result1、result2和差异。我希望这有帮助。
vector<int> p1,p2;
vector<int> result1,result2;
vector<int> array={12,323,432,4,55,223,45,67,332,78,334,23,5,98,34,67,4,3,86,99,78,1};
void partition(unsigned int i,long &diffsofar, long sum1,long sum2)
{
if(i==array.size())
{
long diff= abs(sum1 - sum2);
if(diffsofar > diff)
{
result1 = p1;
result2 = p2;
diffsofar = diff;
}
return;
}
p1.push_back(array[i]);
partition(i+1,diffsofar,sum1+array[i],sum2);
p1.pop_back();
p2.push_back(array[i]);
partition(i+1,diffsofar,sum1,sum2+array[i]);
p2.pop_back();
return;
}
我最近遇到了同样的问题,我发布了一个关于它的问题(这里:Variant of Knapsack)。在我的情况下,不同之处在于结果子集的大小必须相同(如果原始集合具有偶数个元素)。为了确保这一点,我在@Sandesh Kobal 的答案中添加了几行;
void partition(unsigned int i,long &diffsofar, long sum1,long sum2)
{
int maxsize = (array.size()+1)/2;
if(p1.size()>maxsize)
return;
if(p2.size()>maxsize)
return;
if(i==array.size())
{
...
此外,在两次调用之后partition
,我添加了if(diffsofar==0) return;
. 如果我们已经找到了最佳解决方案,那么继续搜索是没有意义的……
我看过的所有文章都采用动态编程方法。我们真的需要一个吗?
假设给定的数组是arr
使用以下算法:
a = []
然后b = []
sum_a = sum_b = 0
for x in arr:
if sum_a > sum_b:
b.append(x)
sum_b += x
else:
a.append(x)
sum_a += x
sum_a
和之间的绝对差异sum_b
是两个子集之间可能的最小差异。
考虑arr = [3,1,1,2,2,1]
对数组进行排序:arr = [3,2,2,1,1,1]
a = [], b = []
a = [3], b = []
a = [3], b = [2]
a = [3], b = [2,2]
a = [3,1], b = [2,2]
a = [3,1,1], b = [2,2]
a = [3,1,1], b = [2,2,1]
sa = 5, sb = 5
最小差异:5 - 5 = 0