选择总和为零的数字

时间:2012-03-17 22:24:11

标签: algorithm breadth-first-search

有N个集合,每个集合包含不同数量的整数,例如:

(-2, -1, 0), (-1,4), (-2, 2, 3), (-3, -2, 4, 6), (-2)

如何从每组中精确选择一个数字,使这些N个整数总和为零?例如:

-1, -1, 2, -2, 4, -2

注意可能没有解决方案或多个解决方案(在这种情况下,我选择哪一个并不重要)。

我以为我可以先进行一次呼吸搜索但是想知道是否有其他方法,最好是更快的方法来解决这个问题。

2 个答案:

答案 0 :(得分:1)

这似乎与subset sum problem有关:给定一组 n 整数,是否有一个总和为0的子集?已知这个问题是NP-complete,简而言之,这意味着你很难找到一种快速的方法。

对于一组整数,它很难,在你的问题中,添加了另一个约束,即必须从每个集合中选择一个整数。搜索算法确实是可行的方法,但在最糟糕的情况下,您将无法比详尽的搜索做得更好。

答案 1 :(得分:1)

如果我们可以使用每个集dp[i, j] = true中的一个数字来计算j,请1, 2, ..., i

dp[i, 0] = true for all i
for i = 1 to numSets do
  for num = 1 to sets[i].Count do
    for j = maxSum - sets[i, num] downto -maxSum do
      dp[i, j + sets[i, num]] |= dp[i - 1, j] 

您可以使用地图处理负数索引或添加偏移量以使其成为正数。 maxSum是您的总和可以采用的最大值(例如,所有集的最大值之和或最小值的绝对值之和,以较大者为准)。可能有一些方法可以在您进行优化时更新maxSum

对于您的示例,这将运行如下:

(-2, -1, 0), (-1,4), (-2, 2, 3), (-3, -2, 4, 6), (-2)

对第一组进行迭代将得到dp[1, -2] = dp[1, -1] = dp[1, 0] = true

对第二个进行迭代将给出dp[2, -3] = true (because dp[2, -2 + -1] |= dp[1, -1] = true), dp[2, -2] = true (because dp[2, -1 + -1] |= dp[1, -1] = true)等。

如果dp[numSets, 0] = true,则有一个解决方案,您可以通过跟踪每个dp[i, j]选择的最后一个数字来重建。

复杂度为O(numSets * K * maxSum),其中K是集合的元素数量。这是假多项式。如果你的价值很小,它可能足够快。如果你的价值很大,但你的几个元素很少,你最好用回溯来强制它。