具有非零目标总和的子集和变体

Subset sum variant with a non-zero target sum

本文关键字:子集 和的 目标      更新时间:2023-10-16

我有一个整数数组,需要对其应用子集和算法的变体,除了不是找到一组总和为 0 的整数,而是我试图找到一组总和为 n 的整数。 我不清楚如何将标准子集和算法之一适应这种变体,并希望对这个问题有任何见解。

这是子集和问题,它是NP-Complete(NP-Complete问题没有已知的有效解决方案),但是如果你的数字是相对较小的整数 - 有一个有效的伪多项式解,在循环之后

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)

稍后,您需要退后一步,查看您决定在生成的矩阵上"减少"(获取元素)的位置,以及您决定不"减少"(不获取元素

)的位置。此线程

和此线程讨论如何获取类似问题的元素。

这是一个python代码(取自我链接到的线程)可以解决问题。
如果你不熟悉python - 把它当作伪代码来阅读,很容易理解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

您可以使用动态编程来解决此问题。

让我们假设:

  • N - 是所需的总和(您的第一个输入)。
  • M - 是可用的汇总数(您的第二个输入)。
  • ...aM - 是可用的总和。
  • f[x]true当你可以达到x的总和时,否则false

现在的解决方案:

最初f[0] = truef[1..N] = false - 我们只能达到零的总和,而无需取任何求和。

现在,您可以遍历所有i,其中 i 在 [1..M] 中,并执行下一个操作:

f[x + a i] = f[x

+ ai] || f[x],对于 [M..ai] - 处理顺序是相关的!

最后输出 f[N]。

此解决方案具有 O(N*M) 的复杂性,因此当您具有大量输入数字或大量总和时,它不是很有用。