子集和变化

时间:2015-09-26 14:26:56

标签: algorithm dynamic-programming subset-sum

给定一组不同大小的ns个整数,但从0s_i的正数为正数。在这里定义一个好的总和为a_1 + a_2 + ... + a_s = n。当你从它的相应集合a_i中获取每个s_i个元素时,计算存在多少总和。

我尝试生成任何可能的方法并省略那些可省略的方法,例如当你有s=3n=1时,你会得到集合s_0={0,1},{{1} },s_1={0,1,2,3},然后您可以省略对s_2={0,1,2}总和的检查,因为0 + 0 + a_3不会足够大。 我已经为每个可能的序列应用了正常子集和的动态编程解决方案,但是,我得到的结果比我应该的要大得多,而且速度也很慢。

我可以在这里申请哪些好的算法吗?

1 个答案:

答案 0 :(得分:1)

你可以通过使用两个字典(数组也可以工作,但字典更好)来实现经典子集求和解的微小变化:

dp[i] = dictionary of sums we can obtain using the first i sets and their counts


dp[0, <elements in s[0]>] = 1
for i = 1 to s - 1:
  for each element x in dp[i - 1]:
    for each element k in s[i]:
      dp[i, x + k] += dp[i - 1, x]

复杂性将会非常大,但我认为没有太多可以做到的减少它。它应该工作。

你只能在内存中保留两个词典,因为你只需要当前和以前的词典。

Python代码:

def solve(s, n):

    dp = [dict()] * len(s)

    for k in s[0]:
        dp[0][k] = 1
    for i in range(1, len(s)):
        dp[i] = dict()
        for x in dp[i - 1]:
            for k in s[i]:
                if x + k in dp[i]:
                    dp[i][x + k] += dp[i - 1][x]
                else:
                    dp[i][x + k] = dp[i - 1][x]

    return dp[len(s) - 1][n]

print(solve([[0,1,2],[0,1,2]], 3)) # prints 2
print(solve([[0,1,2],[0,1,2,3,4],[0,1,2,3,4]], 5)) # prints 13