algorithm - 子集和变化

标签 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}, s_1={0,1,2,3}, s_2={0,1,2} ,那么您可以省略对总和 0 + 0 + a_3 的检查,因为 a_3 不够大。 我已经为每个可能的序列应用了正常子集总和的动态规划解决方案,但是,我得到的结果比我应该得到的要大得多,而且速度也很慢。

有什么好的算法可以在这里应用吗?

最佳答案

您可以通过使用两个字典(数组也可以,但字典更好)对经典的子集求和解决方案进行细微的改动:

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

关于algorithm - 子集和变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32798225/

相关文章:

java - 在 Java 中比较数组

algorithm - 将一组 2n 个整数划分为两个 n 个整数的子集,其总和为正

寻找子集组合以实现给定总和同时保持成本最低的算法

java - A*算法的问题

c - 地址值更改不会反射(reflect)在 while 循环中

algorithm - 自下而上的动态规划可以在 Lisp 中完成吗?

algorithm - 查找树上的最小调用次数

algorithm - 子集和枚举的时间复杂度

algorithm - 大于或等于目标的数的倍数之和,优化

c# - 找到包含查询数组所有元素的输入数组的最小窗口