如何枚举单个组合的组合

时间:2012-10-22 13:47:13

标签: algorithm math recursion combinations combinatorics

我意识到有很多关于组合和枚举的问题,但我已经四处寻找,并没有发现任何与我所追求的有关的内容。如果我错过了什么,请指出我,问题可以关闭。

所以,假设我们有一组N个元素,并且我们有x个正整数k1,...,kx,其中Sum(k1,...,kx)< = N.我想列举所有方法我可以从原始的N组中选择(不替换)给定大小的x个子集。

我希望我说的正确。如果我没有,一个简单的例子 N = 4,x = 2,k1 = 2,k2 = 1。

我们应该枚举

  • {1,2} {3}
  • {1,2} {4}
  • {1,3} {2}
  • {1,3} {4}
  • {1,4} {2}
  • {1,4} {3}
  • {2,3} {1}
  • {2,3} {4}
  • {2,4} {1}
  • {2,4} {3}
  • {3,4} {1}
  • {3,4} {2}

在一般情况下,我认为总计数为:

C(N,k1)* C(N-k1,k2)* ... * C(N-Sum(k1,...,kn-1),kn)。

我最初的猜测是,这可以使用堆栈相当容易地完成。在每个堆栈级别i,将使用标准组合枚举生成子集ki,或者从每个级别的源集合中移除已经选择的元素,或者仅从原始集合中枚举并跳过之前已经包括元素的情况。

我的问题是,是否有更快/更优雅的解决方案?

1 个答案:

答案 0 :(得分:2)

您的问题正是枚举多集的排列问题。 (假设您的k i 已订购)。

首先,注意问题完全等同于Σk= N的问题,因为如果Σk< N,我们可以简单地添加k x + 1 ,其值为N - Σk。

现在,将原始集合S的元素置于某个任意固定的顺序,并生成由k 1 1,k 2 2,k组成的多集合的每个排列。 3 3's,... k x x's。这个多集合具有相同的S(S)大小,因为k i 的加起来为N.我们通过将S中的每个元素分配给索引为对应的子集来创建S的分区。多重集的排列值。

例如,S = {apple,banana,chirimoya,date}(N = 4)。我们取k 1 = 2并且k 2 = 1并且添加k 3 = 1以使总和为4.(我们只是忽略分配给子集3的元素。现在我们列举多重集1 1 2 3的排列(它有两个1,一个2和一个3,对应于k):

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

我们将这些转换回S的分区。例如,取1 3 1 2

apple     1 -> subset 1
banana    3 -> unused
chirimoya 1 -> subset 1
date      2 -> subset 2

所以我们有{{apple, chirimoya}, {date}}

用于查找集合的排列的standard algorithm在多集合上也可以正常工作,尽管如果多集合有很多重复,它并不是最佳的。