views:

760

answers:

4

The problem is the following:

You are given a set of positive integers { a1 , a2 , a3 , ... , an } in which there are no same numbers ( a1 exists only once ,a2 exists only once,...) eg A = {12 , 5 ,7 ,91 }. Question: Are there two disjoint subsets of A , A1 = { b1,b2,...,bm } and A2 = { c1,c2,...,ck} so that b1+b2+...+bm = c1+c2+...+ck ?

Note the following: It is not obligatory for A1 and A2 to cover A, so the problem isn't automatically reduced to the subset sum problem. eg A = {2,5,3,4,8,12} A1= {2,5} so sum of A1 is 7 A2= {3,4} so sum of A2 is 7 We found two disjoint subsets of A with the described property so the problem is solved.

How can I solve this problem? Can I do something better than find all possible (disjoint)subsets, calculate their sums and find two equal sums?

Thank you for your time.

+1  A: 

No problem, here's an O(1) solution.

A1 = {}; 
A2 = {};
sum(A1) == sum(A2) /* == 0 */

QED.


Seriously, one optimization you can make (assuming that we're talking about positive numbers) is to only check sub-sets less or equal to sum(A)/2.

For every element in A there are three options which makes it O(3^N):

  1. Put it in A1
  2. Put it in A2
  3. Discard it

Here's a naive solution in Perl (that counts the matches, you can have an early return if you just want to test existence).

use List::Util qw/sum/;

my $max = sum(@ARGV)/2;
my $first = shift(@ARGV); # make sure we don't find the empty set (all joking aside) and that we don't cover same solution twice (since elements are unique)
my $found = find($first,0, @ARGV);
print "Number of matches: $found\n";

sub find {
    my ($a, $b, @tail) = @_;
    my $ret = $a == $b? 1 : 0; # are a and b equal sub-sets?
    return $ret unless @tail;

    my $x = shift @tail;
    $ret += find($a + $x, $b, @tail) if $a + $x <= $max; # put x in a
    $ret += find($a, $b + $x, @tail) if $b + $x <= $max; # put x in b
    return $ret + find($a, $b, @tail); # discard x
}
Motti
The O(2^N) solution mentioned in the question is better than this O(3^N) solution :-) [At the cost of taking requiring O(2^N) space as well.]
ShreevatsaR
Yeah, but my O(1) solution still trumps it ;o)
Motti
Definitely. Flawless O(1) solution. :-)
ShreevatsaR
+1  A: 

If the answer is no, then the sum of all n numbers is at least 2^n-1. So if n is large, and the numbers are 32-bit integers, for instance, then the answer is almost always yes. If n is small, you can probably brute-force.

The hardest case is probably when n is around 30.

mattiast
A: 

I think that you can solve it just like the subset sum problem. Take the boolean function Q(i,s) which is true if a0,a1,...,ai have a subset that sums to s and contains ai. You can compute it for all i and s using dynamic programming (this is the standard approach). Then, you can scan all values of Q for s that has more than one true value in its associated row.

If such s exists, it means that you found two different subsets that have the same sum. They might not be disjoint, but then you can remove the common elements from each set and get two disjoint sets with equal sums. One of them might be empty, though.

Rafał Dowgird
A: 

This problem seems to be at least as hard as SUBSET-SUM. If we can find two subsets of A: B = {b1,...,bp} and C = {c1,...,cq} such that b1+...+bp = -c1-...-cq, or if we determine that none exist, then we have solved SUBSET-SUM(A) (ignoring the trivial case where 0 ∈ A).

I'm not sure what you mean by it is not obligatory for B and C to cover A, so the problem isn't automatically reduced to the subset sum problem. Please check the definition of SUBSET-SUM.

Imran