【问题标题】:Subset sum variation: Get as many subset sums as possible子集和变化:获取尽可能多的子集和
【发布时间】:2017-01-01 14:35:19
【问题描述】:

对于碎片整理算法,我需要解决以下问题: 给定一组正整数,尽可能多地提取总和为给定值的子集。集合中的每一项只能出现在一个子集中。

贪心算法(迭代正态子集和)不起作用,反例:

collection: 3 5 8 4 5 1 1 1 1 1, targeted sum: 10
1. subset: 5 1 1 1 1 1
there is no other subset

but:
1. subset: 8 1 1
2. subset: 5 4 1
3. subset: 3 5 1 1

如您所见,如果我选择的先前子集不好,则解决方案不是最优的。 我该如何解决这个问题?我已经实现了“正常”子集总和。

编辑:解决方案可能是先使用小子集吗?此外,这个问题与如何找到可能的子集数量的问题没有重复。我想找到尽可能多的不相交子集。

谢谢,菲尔

【问题讨论】:

  • @Druid: 完全不一样,尽管这可以由此构建:这里的解决方案需要是原始集合的一个分区,其元素肯定来自所有可能子集的列表,但可能不仅是一个真子集,而且其中一些子集是重复的。
  • @Druid 我已经编辑了这个问题以消除这个问题的歧义

标签: algorithm optimization sum subset greedy


【解决方案1】:

如果您允许回溯(即能够返回并撤消先前的决定),那么您可以搜索整个可能性空间并确保找到您的解决方案。不是最有效的,但它确实有效。

或者您可以基于@Druid 的评论:找到所有可能的子集,然后搜索这些子集以找到您的分区,从而允许子集被复制。您可以添加要在较大子集之前尝试较小子集的启发式方法(为将来的选择留出更多灵活性)。

【讨论】:

    【解决方案2】:

    这个问题可能是强 NP-hard*,所以让我画一个 O(2^n * n) 时间的算法。

    令输入为多重集 U,令目标总和为 s。想象一个对应于 U 的子集的 2^n 个顶点上的图。当且仅当 (1) Y = X - {x} 对于 X 中的某个 x,并且 (2) (sum(U - X) mod s) + x ≤ s,即我们不会溢出当前分区。从 U 开始遍历这个图,并报告到总和最小的子集的路径。

    *我显示硬度的减少来自一个名为3-dimensional matching 的问题。给定匹配实例有 n 个顶点,找到 n 个数,使得所有三元组的和都不同。应用概率方法,如果我们从 1..n^6 中均匀地随机选择所有 n,则成功的概率大于 11/12(一减(n 选择 3)选择 2 三倍乘以 my question on math.SE。

    要准备此问题的输入,对于与数字 x 关联的每个顶点,输出 n^12 + x。对于每个可以匹配的三元组 x、y、z,输出 n^9 - x - y - z 作为数字。目标是 s = 3 n^12 + n^9。一些繁琐的数学应该表明只有具有目标总和的子集对应于 3 维匹配的三元组。

    【讨论】:

    • 感谢您的回答。你有反例吗,为什么我不能简单地找到最小的子集,删除这些元素并从剩余的元素重新开始,直到找不到子集?
    • 请注意:一个问题是严格意义上的 npc,因为它是一个泛化的 npc 问题,3-partition。
    • @user3151250 97, 11, 11, ..., 11, 1, 1, 1,27个11,目标总和100。右分区是9个11和一个1,3次, 但最小的第一个需要 97, 1, 1, 1 并卡住。
    • 我发现您提出这个解决方案的方式令人印象深刻。这是具有特定名称的标准问题吗?我找不到任何东西。
    • @user3151250 这有点与装箱有关,但我的算法设计策略只是为了记住回溯搜索。
    【解决方案3】:

    对于问题的复杂性,是强意义上的NPC。这是3-Partition问题的后续:

    给定一个 n = 3 m 正整数的多重集 S,S 可以被分区吗 分成 m 个三元组 S1, S2, ..., Sm 使得每个数的总和 子集是否相等?子集 S1, S2, ..., Sm 必须形成 S 的一个分区 从某种意义上说,它们是不相交的,并且覆盖了 S。

    我们需要一个来自三分区问题的额外信息(这是其硬度证明的直接结果):

    令 B 表示每个子集 Si 的(期望的)总和,或者等价地,令 S 中的数字的总和为 m B。当 3 分区问题保持 NP 完全时S 中的每个整数都严格介于 B/4 和 B/2 之间。

    对于您的问题,我们可以假设输入由 3m 个元素组成,给定值为 B 并且对于每个元素 a∈S 我们有 B/4 。然后我们可以找到 m 个集合,当且仅当我们可以解决三个分区时,它们中的每个集合都有总和 B。 (请注意,范围约束会自动强制每个集合中包含 3 元素)。

    【讨论】:

      【解决方案4】:

      我创建了一个递归过程来查找所有子集总和。它主动决定集合中的数字是否太大或太小而不能成为父节点。我用 Nodejs 写了一个运行良好的程序。只需重新访问它以优化和重构代码。

      对于一个全是正数的集合,可以对我的代码进行许多启发式和优化。

      你可以在这里阅读我手工计算的数学: https://medium.com/@clint.mulligan/innovative-solution-to-the-subset-sum-problem-10a19f87056b

      以及此处的代码链接: https://github.com/ClintMulligan/subset-sum-finder.

      本质上,集合是排序的。第一个数字被视为包含在一般树中的父节点。相关数据 bieing 数字所属的整数集合,即正数或负数。

      太大而不能成为父节点是|n| > |目标总和-(相反组)| 并且太小是(同一组)

      如果其中任何一个为真,则考虑下一个数字。如果它们都为假,则将 Number 作为节点移动,并创建目标 Sum 减去 Number 和剩余集合的新子问题。这样做直到每个子问题都以解决方案或死胡同结束。

      通过使用一些优化和进一步调查,我希望消除最死胡同。这还不错吧。

      【讨论】:

        猜你喜欢
        • 2015-12-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-28
        • 1970-01-01
        • 2018-01-29
        • 2011-05-03
        相关资源
        最近更新 更多