【问题标题】:Number of distinct sums of subsets子集的不同总和的数量
【发布时间】:2013-07-27 14:07:23
【问题描述】:

我有一组 N,对于 N>3,不同的整数,问题是找到给定集合的 3 个子集的所有不同和。 3 子集是基数为 3 的子集。

我知道愚蠢的方法是对所有可能的总和进行三次搜索,然后对所有重复项进行排序。有没有更有效的方法来做到这一点?我正在用 C 语言编程。

编辑:如果元素数量增加,我想知道一个通​​用的更快算法。

【问题讨论】:

  • 如果你只有 8 个整数,三次搜索会很快。为什么你需要为这么少的元素提供更好的东西?
  • 不是骗子,而是相关的:Sum-subset with a fixed subset size。请注意,找到所有非固定大小的子集总和是 NP-Complete [更正:NP-Hard]。
  • 亲密选民:这个问题有什么问题?算法问题非常好并且符合主题。不仅是“如何在 C 中解析字符串?”适合 SO 的问题,这些也非常好,因为在算法建立后,它可以很容易地用任何编程语言编程。
  • 天真的解决方案并不完全是立方时间,而是有点困难:O(N^3 * log N):我们需要对重复项进行排序,这就是 O(N^3 * log (N^3)) 出现。问题是我们是否可以在 O(N^3) 中实现(因为我们当然不能让它比 O(N^3) 更快,因为 O(N^3) 是 3-subsets 的数量)。
  • 如果你想找到 3 个子集的所有不同的和,那么复杂度至少是不同和的数量(因为我们需要找到并输出它们中的每一个),这是 O (N^3) 在最坏的情况下。如果您只想找到不同总和的数量,那会改变问题(但我不确定这是否会简化它)。

标签: c algorithm


【解决方案1】:

如果您怀疑您可能有很多重复的总和,那么您可以先计算所有不同的 2 子集总和,对于您找到的每个不同的 2 子集总和,跟踪您找到的哪一对给您和。如果你所有的数字都是不同的,那么如果你找到另一对给你相同的总和,你应该将总和标记为“多个”,如果你愿意,你可以删除你为它存储的那对。现在你有一组 2 子集和,每个和要么有一对存储在一起,要么被标记为“多个”。对于每个 2 子集总和,如果它被标记为“多个”,那么您遍历原始集中的所有数字并记录您可以通过将每个数字添加到 2 子集总和来形成的所有 3 子集总和。否则,如果 2 子集总和未标记为“多个”并且您有一对 (a,b) 与之关联,那么您将执行相同的操作,只是在迭代原始数字集时跳过 a 和 b .这就是您获得所有不同的 3 子集总和的方式。如果你有 n 个数字并且它们产生 N 个不同的 2 子集和,那么如果你在算法的两个阶段使用哈希表来检测重复项,那么这种方法的复杂度是 O(nN),这可能比 brute 要好得多强制 O(n^3 log n),特别是如果你有一组相当密集的整数。

【讨论】:

  • 请注意,如果您正在寻找 4 子集总和,这种解决方案可能会更加有益;在这种情况下,如果您有 N 个不同的 2 子集和,则基本上可以获得 O(N^2) 的复杂度,而如果您的原始集合中有 n 个数字,则复杂度为 O(n^4 log n)。
  • 感谢您的回答,即使我正在考虑这个问题。但是,我仍然相信有更快的算法。
  • 我同意,应该有某种妥协,你基本上将动态编程方法作为主要步骤,但仅限于输入的“密集的小整数”部分,所以你不要如果您有少量大整数异常值,就不会出现疯狂的复杂性爆炸。但是,我认为将这个想法变成一个定义明确的算法,对于定义明确的输入类型具有可证明的良好复杂性,这会很麻烦。
  • 我认为您的算法中有一点我遗漏了:假设有数字 1、2、3、4。然后你会得到与 (1,2) 和 5 相关联的 2 子集总和 3 标记为“多个”。现在如何防止 6 被计算为 3+3 和 5+1?
【解决方案2】:

使用动态规划,您可以在O(n*MAX) 中找到不同和的个数,其中MAX 是数组中的最大值。

我们来看看递归函数:

f(W,n,i) = f(W,n-1,i) OR (i != 0 ? f(W-item(n),n-1,i-1) : false)
f(0,0,0) = true
f(W,n,0) = false (W != 0)
f(W,0,i) = false (W != 0)
f(W,n,i) = false (W < 0)
(I have a feeling I forgot another failing base clause, so make sure if I didn't)

现在,如果你使用动态编程构建这个自下而上的方法,直到 W=3*MAX,你的答案基本上就是 f(W,n,3) == true 对他们来说不同的 Ws 的数量。

构建表将是O(MAX*3 * n * 3) = O(MAX*n),计算不同Ws 的数量并给出所需总和的后处理阶段是O(MAX),因此解决方案仍然是O(MAX * n)

【讨论】:

  • 一个不错的动态编程解决方案。这也需要 O(MAX) 的内存。该算法不仅可以找到数字,还可以找到所有不同的和。目前还不清楚 O(n*MAX) 是否比 O(n^3 * log n) 更有效,这当然取决于n 和 MAX。
  • 投反对票:为什么投反对票? OP 说(在 cmets 中)他对找到不同总和的 number 的解决方案感兴趣:@amit I am interested in solving any way, mon cher ami! Please do!
  • 由于对 MAX 的敏感性,在使用这种方法时必须非常小心。如果您可以概括为仅处理密集/小数字的输入部分,然后使用传统方法来处理输入中的任何大整数,那将会很有趣。如果大整数的比例很低,这应该是一个很好的折衷方案,因为直观地说,如果大整数足够大且随机,那么它们每个都会与 2 子集和组成一组 3 子集和,使得 3 -对于大整数的不同选择,子集和集几乎是不相交的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-21
  • 1970-01-01
相关资源
最近更新 更多