Subset sum variant with a non-zero target sum

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-25 18:34:24

问题


I have an array of integers and need to apply a variant of the subset sum algorithm on it, except that instead of finding a set of integers whose sum is 0 I am trying to find a set of integers whose sum is n. I am unclear as to how to adapt one of the standard subset sum algorithms to this variant and was hoping for any insight into the problem.


回答1:


This is subset sum problem, which is NP-Complete (there is no known efficient solution to NP-Complete problems), but if your numbers are relatively small integers - there is an efficient pseudo polynomial solution to it that follows the recurrence:

D(x,i) = false   x<0
D(0,i) = true
D(x,0) = false   x != 0
D(x,i) = D(x,i-1) OR D(x-arr[i],i-1)

Later, you need to step back on your choices, see where you decided to "reduce" (take the element), and where you decided not to "reduce" (not take the element), on the generated matrix.

This thread and this thread discuss how to get the elements for similar problems.

Here is a python code (taken from the thread I linked to) that does the trick.
If you are not familiar with python - read it as pseudo code, it's pretty easy to understand python!.

arr = [1,2,4,5]
n = len(arr)
SUM = 6
#pre processing:
D = [[True] * (n+1)]
for x in range(1,SUM+1):
    D.append([False]*(n+1))
#DP solution to populate D:
for x in range(1,SUM+1):
    for i in range(1,n+1):
        D[x][i] = D[x][i-1]
        if x >= arr[i-1]:
            D[x][i] = D[x][i] or D[x-arr[i-1]][i-1]
print D

#get a random solution:

if D[SUM][n] == False:
    print 'no solution'
else:
    sol = []
    x = SUM
    i = n
    while x != 0:
        possibleVals = []
        if D[x][i-1] == True:
            possibleVals.append(x)
        if x >= arr[i-1] and D[x-arr[i-1]][i-1] == True:
            possibleVals.append(x-arr[i-1])
        #by here possibleVals contains 1/2 solutions, depending on how many choices we have.
        #chose randomly one of them
        from random import randint
        r = possibleVals[randint(0,len(possibleVals)-1)]
        #if decided to add element:
        if r != x:
            sol.append(x-r)
        #modify i and x accordingly
        x = r
        i = i-1
    print sol



回答2:


You can solve this by using dynamic programming.

Lets assume that:

  • N - is the sum that required (your first input).
  • M - is the number of summands available (your second input).
  • a1...aM - are the summands available.
  • f[x] is true when you can reach the sum of x, and false otherwise

Now the solution:

Initially f[0] = true and f[1..N] = false - we can reach only the sum of zero without taking any summand.

Now you can iterate over all ai, where i in [1..M], and with each of them perform next operation:

f[x + ai] = f[x + ai] || f[x], for each x in [M..ai] - the order of processing is relevant!

Finally you output f[N].

This solution has the complexity of O(N*M), so it is not very useful when you either have large input numbers or large number of summands.



来源:https://stackoverflow.com/questions/30899356/subset-sum-variant-with-a-non-zero-target-sum

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!