如何有效地迭代恒定总和的数组组合?

时间:2012-12-21 10:16:06

标签: algorithm

我有一个数组,其长度为X。数组的每个元素都有范围1 .. L。我想有效地迭代所有具有总和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)。

有人能告诉我这个问题是如何调用的,或者在哪里找到问题的快速算法?

谢谢!

1 个答案:

答案 0 :(得分:8)

如果我理解正确,你会得到两个数字1≤ X L 你想要生成长度为 X <的所有正整数序列/ em>总和为 L

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

您要查找的序列对应于 X combinations - L 中的1项 - 1.因为,如果我们输入数字按顺序1到 L - 1,并选择 X - 其中1个,然后所选数字之间的间隔长度为正整数,总和为 L < / em>的

例如,假设 L 为16且 X 为5.然后选择1到15之间的4个数字:

the four numbers 3, 7, 8, and 14 are chosen from 1 to 15

在开头添加0,在结尾添加16,间隔为:

intervals 0–3, 3–7, 7–8, 8–14 and 14–16

根据需要

和3 + 4 + 1 + 6 + 2 = 16.

X generate the combinations - L - 1中的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 的组合 - L - 1中的1项,因此该算法的运行时间(及其输出的大小)在 L 。但是,如果不计算输出,则只需要O( L )空间。

L = 128且 X = 8,有89,356,415,775个分区,所以输出它们需要一段时间!

(也许如果你解释为什么要计算这些分区,我们或许可以建议一些满足你需求的方法,而不必实际生成它们。)