简体   繁体   中英

how can i reduce the time complexity of subset sum problem

So lately I have been trying to solve some interesting problems,, but got quite stuck on this one.

Given a set of objects 1 to N. n1 objects with value 0 and n2 objects with value 1 and n3 objects with value 2. Need to count all the subsets with sum 3 or its multiple.

n1+ n2 + n3 = N <= 100000 the value of n1, n2 and n3 can be 0 as well, while fulfilling the above condition.

I have been able to solve the problem but not able to bring down the time complexity of this problem. My solution still has exponential time complexity. I am trying to bring the time complexity down so that I can run for large set with N = 100,000 under 5 secs.

This is another simple but intutive solution I stumpled on but again time complexity is the problem.

def mask(lst, m):
    # pad number to create a valid selection mask
    # according to definition in the solution laid out
    m = m.zfill(len(lst))
    return map(lambda x: x[0], filter(lambda x: x[1] != '0', zip(lst, m)))

def subset_sum(lst, target):
    # there are 2^n binary numbers with length of the original list
    for i in range(2**len(last)):
        # create the pick corresponsing to current number
        pick = mask(lst, bin(i)[2:])
        if sum(pick) == target:
            yield pick

I don't need the exact coded solutions, but would be great if you can point me in the right direction and any programming language would be okay, I would like to know the logic/approach of the solution.

It seems like, given an array of numbers (all of which are 0, 1 or 2), you want to return every subset of these numbers that sum to a multiple of 3, and you want to do it polynomially.

This is impossible.

To see this, consider the array [2,1,0,0,0,0,0,...,0]. To get to a sum of 3 we will always require the first two numbers, but apart from that any subset sums to 3. As we have N-2 0s, that gives a total amount of 2**(N-2) subsets that fit the requirement. Returning an exponential amount of answers cannot be done in polynomial time.

So a key knowledge here is that the sum must be a multiple of 3, that is sum = 0 (mod 3).

This means you can include as many or as few of n1 as you want in any subset as they don't change the sum.

So you can immediately reduce the problem to finding subsets from n2 and n3 that sum to 0 (mod 3) and then add on all possible 2**n1 subsets to these. Note that for any signicant value of n1 (like above 50) this becomes uncomputable to list them.

It is however easy to count:

So how to go about finding the sets from n2 and n3 that have sum = 0 (mod 3). We know that any element from n2 increases the sum by one, given m elements from n2 we can calculate how many elements are possible from

so a loose pseudo code for counting:

def f(n1,n2,n3):
    for i in range(0,n2+1):
        # i elements of n2
        # compute i%3
        # if i%3 0 then we can pick j = 0,3,6,9 ... elements from n3
        # if i%3 1 then we can pick j = 1,4,7,10 .. elements from n3
        # if i#3 2 then we cannot j = 2, 5, 8, 11 .. elements from n3
        # compute the combination c = (n choose i) * (n choose j) for each j
        # for each c multiply by 2**n1 (adding on all possible subsets from n1)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM