生成所有"无需替换"子集系列

时间:2018-06-18 06:30:42

标签: combinatorics pseudocode

我正在寻找一种方法来生成集合的所有可能的子组合,其中每个元素最多可以使用一次。

例如,集合{1,2,3}将产生

{{1},{2},{3}}
{{1},{2,3}}
{{1,2},{3}}
{{2},{1,3}}
{{1,2,3}}

伪代码提示会很棒。此外,如果有一个术语或适用的术语,我很乐意学习它。

1 个答案:

答案 0 :(得分:2)

首先,一些指示。

将一个集合分离为不相交的子集称为集合分区(WikipediaMathWorld)。

编码集合分区的常用方法是restricted growth string

设置分区的数量是Bell number,并且它们增长很快:对于一组20个元素,有51,724,158,235,372个设置分区。

以下是编码的工作原理。 按递增顺序查看元素:1,2,3,4,.... 设c为当前的子集数,最初为0。 每当当前元素是其子集的最低元素时,我们为此集分配数字c,然后将c增加1。 无论如何,我们写下包含当前元素的子集的编号。

从过程开始,字符串的第一个元素将是0,并且每个下一个元素不大于到目前为止的最大值加1。因此,名称,"限制增长字符串"。

例如,考虑分区{1,3},{2,5},{4}

元素1是其子集中最低的,因此子集{1,3}0标记。
元素2是其子集中最低的,因此子集{2,5}1标记。
元素3位于已由0标记的子集中 元素4是其子集中最低的,因此子集{4}2标记。
元素5位于已由1标记的子集中。

因此我们得到字符串01021。 字符串告诉我们:

元素1位于子集0中 元素2位于子集1中 元素3位于子集0中 元素4位于子集2中 元素5位于子集1中。

为了从不同的角度来理解它,这里是四元素集的所有分区,以及相应的减少的增长字符串:

0000      {1,2,3,4}
0001      {1,2,3},{4}
0010      {1,2,4},{3}
0011      {1,2},{3,4}
0012      {1,2},{3},{4}
0100      {1,3,4},{2}
0101      {1,3},{2,4}
0102      {1,3},{2},{4}
0110      {1,4},{2,3}
0111      {1},{2,3,4}
0112      {1},{2,3},{4}
0120      {1,4},{2},{3}
0121      {1},{2,4},{3}
0122      {1},{2},{3,4}
0123      {1},{2},{3},{4}

对于伪代码,生成所有这些字符串相对简单。 我们递归地做。 保持值c,将包含0c的每个数字分配给当前位置,并且对于每个这样的选择,递归地构造字符串的其余部分。 也可以懒惰地生成它们,从带有全零的字符串开始,并重复查找按字典顺序排列的下一个字符串,类似于next_permutation用于list all permutations的方式。

最后,如果您希望看到更多内容(以及提到的next功能),请进行一些自我宣传。 最近,我们在我的大学做了一个学习项目,要求学生以合理的效率实现组合对象的各种功能。 Here是限制增长字符串的部分;我链接了描述函数的标题部分。