【发布时间】:2013-01-30 01:16:05
【问题描述】:
我正在寻找一种算法和/或 Python 代码来生成将一组 n 元素划分为零组或多组 r 元素和余数的所有可能方法。例如,给定一个集合:
[1,2,3,4,5]
有n = 5和r = 2,我想得到
((1,2,3,4,5),)
((1,2),(3,4,5))
((1,3),(2,4,5))
...
((1,2),(3,4),(5,))
((1,2),(3,5),(4,))
...
也就是说,从集合中抽取0组2项的结果,加上从集合中抽取1组2项的结果,再加上从集合中抽取2组2项的结果,...如果n 更大,这将继续。
生成这些结果的顺序并不重要,每个单独组中元素的顺序也不重要,结果中组的顺序也不重要。 (例如((1,3),(2,4,5)) 等价于((3,1),(4,5,2)) 和((2,5,4),(1,3)) 等等。)我正在寻找的是每个不同的结果至少产生一次,最好是一次,以尽可能有效的方式.
蛮力方法是从n元素中生成r的所有可能组合,然后创建任意数量的这些组合的所有可能组(powerset),迭代它们并只处理组中的组合没有共同元素的组合。即使是少量元素,这也花费了 far 太长的时间(它需要迭代 2^(n!/r!(n-r)!) 个组,因此复杂度是双指数的)。
基于this question 中给出的代码,这基本上是r = 2 和n 的特例,我想出了以下内容:
def distinct_combination_groups(iterable, r):
tpl = tuple(iterable)
yield (tpl,)
if len(tpl) > r:
for c in combinations(tpl, r):
for g in distinct_combination_groups(set(tpl) - set(c), r):
yield ((c,) + g)
这似乎会产生所有可能的结果,但它包含一些重复项,当n 相当大时,它们的数量是不平凡的。所以我希望有一种算法可以避免重复。
【问题讨论】:
-
这里math.stackexchange.com/questions/222780/…,在答案中,您可以找到Knuth 的《计算机编程的艺术》第4 卷分册3b 的链接
-
@Teudimundo:您的链接是关于将 n 元素的分区找到恰好 k 集的问题,任何大小。但是这里的 OP 希望将 n 元素划分为任意数量的大小正好 r 的集合(可能还有一些余数)。