【问题标题】:How to iterate through array combinations with constant sum efficiently?如何有效地迭代具有常数和的数组组合?
【发布时间】:2012-12-21 10:16:05
【问题描述】:

我有一个数组,它的长度是X。数组的每个元素都有范围1 .. L。我想有效地遍历所有具有 sum L 的数组组合。

正确解:L = 4 和 X = 2

1 3
3 1
2 2

正确解:L = 5 和 X = 3

1 1 3
1 3 1
3 1 1
1 2 2
2 1 2
2 2 1

对于我的问题来说,天真的实现(难怪)太慢了(在我的例子中,X 最高为 8,L 最高为 128)。

谁能告诉我这个问题是怎么命名的,或者在哪里可以找到解决这个问题的快速算法?

谢谢!

【问题讨论】:

  • 在我看来,您好像在寻找长度为 XL整数分区
  • 你不能有效地(在文献中,效率=多项式)。有指数级的解决方案,并且迭代所有这些需要指数级的时间。
  • 这将是一个很棒的项目欧拉问题 =)
  • 我发现您的示例令人困惑,因为您没有提供输入数组。还是当您说“每个元素的范围为 1 .. L”时,您实际上是指“元素 i 等于 i”? (在这种情况下,为什么要提到数组?)

标签: algorithm


【解决方案1】:

如果我理解正确,给你两个数字 1 ≤ XL 并且你想要生成长度为 X 总和为 L

(注意:这类似于integer partition problem,但不一样,因为您认为1,2,2与2,1,2是不同的序列,而在整数分区问题中我们忽略了顺序,因此这些被认为是同一个分区。)

您要寻找的序列对应于 x - 1个项目的 combinations of l l - 1。 L - 1 依次选择X - 1个,则所选数字之间的间隔长度为正整数,总和为L.

例如,假设 L 为 16,X 为 5。然后从 1 到 15 (含)选择 4 个数字:

开头加0,结尾加16,区间为:

根据需要,3 + 4 + 1 + 6 + 2 = 16。

so @ so generate the combinations of x - 1项从 l - 1中取出的项目,对于每个 l - 1,通过查找间隔,将其转换为分区。例如,在 Python 中你可以这样写:

from itertools import combinations

def partitions(n, t):
    """
    Generate the sequences of `n` positive integers that sum to `t`.
    """
    assert(1 <= n <= t)
    def intervals(c):
        last = 0
        for i in c:
            yield i - last
            last = i
        yield t - last
    for c in combinations(range(1, t), n - 1):
        yield tuple(intervals(c))

>>> list(partitions(2, 4))
[(1, 3), (2, 2), (3, 1)]
>>> list(partitions(3, 5))
[(1, 1, 3), (1, 2, 2), (1, 3, 1), (2, 1, 2), (2, 2, 1), (3, 1, 1)]

有 (L - 1)! / (X - 1)!(L - X)! X - 1 个项目中的 L - 1 的组合,因此该算法的运行时间(及其输出的大小)在 L中是指数的>。但是,如果不计算输出,它只需要 O(L) 个空间。

如果 L = 128 和 X = 8,则有 89,356,415,775 个分区,因此需要一段时间才能将它们全部输出!

(也许如果您解释为什么要计算这些分区,我们可能会提出一些方法来满足您的要求,而不必实际生成所有分区。)

【讨论】:

  • 我认为如果你将intervals移出循环并将c作为输入参数传递,我认为这个实现可以稍微优化——这样你就不会为每个组合创建一个新函数.
  • @mgilson:我将函数定义移出循环以使您满意。但面对程序指数级的运行时行为,这种优化似乎是徒劳的。最好弄清楚如何完全避免计算这些分区。
  • 我同意——面对几乎没有希望的任务,这是一个超级小的优化。但是,如果我们要为此编写一个实现,它也可能是一个不错的 :-)
  • 如果 n>t,你将如何扩展它以添加零分区?
猜你喜欢
  • 1970-01-01
  • 2018-02-02
  • 1970-01-01
  • 1970-01-01
  • 2020-01-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-18
相关资源
最近更新 更多