algorithm - 如何从单个集合中枚举组合的组合

标签 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,或者从每个级别的源集中删除已选择的那些元素,或者仅从原始集中枚举并跳过之前已包含元素的情况.

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

最佳答案

您的问题正是枚举多重集排列的问题。 (假设您的 ki 已排序)。

首先,请注意,该问题与 Σk = N 的问题完全相同,因为如果 Σk < N,我们可以简单地添加 kx+1,其值为 N - Σk。 p>

现在,将原始集合 S 的元素按任意固定顺序放置,并生成由 k1 1、k2 2、k 组成的多重集的每个排列3 3,... kx x。这个多重集与 S 具有相同的大小 (N),因为 ki 的总和为 N。我们通过将 S 中的每个元素分配给索引为对应的子集来创建 S 的分区多重集排列中的值。

例如,S = {苹果、香蕉、chirimoya、枣}(N = 4)。我们取 k1 = 2 和 k2 = 1,然后加上 k3 = 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查找集合的排列在多重集上同样有效,尽管如果多重集有很多重复项,则它不是最佳的。

关于algorithm - 如何从单个集合中枚举组合的组合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13012801/

相关文章:

algorithm - 检测重复的行组

php - 列出给定标签的所有建议字段

c - 如何在没有 vector/递归的情况下为类似斐波那契的序列编写 C 程序?

performance - 'recursive' 属性如何影响 FORTRAN90 子例程的性能

java - 如何在递归二分搜索中显示新的中间位置

algorithm - 图问题的函数/流编程 "Reconstruct Itinerary"

c++ - 在文本文件中查找子字符串的最快方法

python - python中的Clauset-Newman-Moore社区检测算法

python - 我的代码中的变量无法正确定义

java - Java 测验(平均猜测)