创建不再有一个交叉元素的组合

时间:2010-06-02 05:56:05

标签: algorithm math combinatorics

我希望创建一种特殊类型的组合,其中没有两个集合具有多个交叉元素。让我用一个例子来解释:

我们说我们有9个字母集,其中包含A,B,C,D,E,F,G,H和I

如果您创建三个字母的标准非重复组合,您将拥有9C3集。 这些将包含ABC,ABD,BCD等集合。我希望创建最多只有1个常用字母的集合。所以在这个例子中,我们将获得以下集合:

ABC,ADG,AEI,AFH,BEH,BFG,BDI,CFI,CDH,CEG,DEF和GHI - 请注意,如果您选择任意两套,则不超过1个重复字母。

生成此类集合的好方法是什么?它应该是可扩展的解决方案,以便我可以为一组1000个字母执行此操作,子集大小为4。

非常感谢任何帮助。

谢谢

5 个答案:

答案 0 :(得分:11)

答案 1 :(得分:3)

我必须添加另一个答案,因为另一个答案已经太长了。

如果您有以下限制条件:

1)你需要每周4人组。

2)某一周的每个小组都是不相交的,每个学生只有一个小组。

3)如果两个学生在同一组,他们将来不需要在同一组。

如果您按如下方式构建图G:

1)每个学生都是一个节点。

2)如果他们之前没有在一个小组中,那么两个学生就会有优势。

随着学生随意下降/加入,这成为一个难题!即使您从最初的图表开始,几周之后,图表也会变得非常难以预测。

你的问题:你需要找到G的生成子图,这样它就是K_4副本的联合,换句话说就是K_4s的分区。

不幸的是,看起来这个问题是NP-Hard:精确覆盖4组(NP-Complete)可以减少到你的问题(就像3套的精确覆盖可以减少分成三角形)

也许这有助于提供一些aproximation算法:http://www.siam.org/proceedings/soda/2010/SODA10_122_chany.pdf

(您的问题可以简化为Hypergraph匹配,因此可以将算法用于您的问题。)

确切封面:http://en.wikipedia.org/wiki/Exact_cover

分成三角形:https://noppa.tkk.fi/noppa/kurssi/t-79.5103/viikkoharjoitukset/T-79_5103_solutions_5.pdf

精确覆盖4组=给定大小为4m的集合S和S的4元素子集的集合C,是否存在C的子集C',使得S的每个元素在C'中恰好出现一次

不幸的是,您可能不得不改变一些限制。

答案 2 :(得分:1)

以下是该算法的一些概要。

  1. 首先找到所有对: AB BC CD DE EF FG GH HI AC BD CE DF EG FH GI AD BE CF DG EH FI AE BF CG DH EI AF BG CH DI AG BH CI AH BI AI
  2. 这些可以存储在sixe n(n-1)

    的数组中
    1. 现在开始尝试使用以下规则组合连续对: 一个。只有存在共同字符时才能组合两对。 湾当通过保留共同特征形成的对也可用时,该组合是可能的。例如如果我们想要结合AB和AC,那么我们需要检查BC是否也可用。 C。当满足上述规则时,我们将两对组合成三元组(例如AB和AC合并形成ABC),并将所有三对标记,例如AB,AC和BC标记为不可用。

    2. 继续这样做,寻找数组中的可用对,并将它们合并形成三元组,并标记对不可用,直到没有可用的对或不再形成三元组。

    3. 实施例: 1.结合AB + AC - > ABC; Mark AB,AC和BC不可用。 2.结合AD + AE - > AED;标记AD,AE和DE不可用。 3.组合AF + AG - > AFG; Mark AF,AG和FG不可用。 ..

答案 3 :(得分:1)

这是一种满足您所述要求的方法。是否做你想要的我不知道。

  1. 在一张大纸上绘制一个至少有250个正方形的规则网格。
  2. 用字母表中的字母标记正方形的边(250格x 4边== 1000)。
  3. 每个方块定义一个子集。每个只与每个(最多)4个邻居共享一侧(即一个字母)。没有一方(即字母)由超过2个方格(子集)共享。
  4. 我会让你把它变成工作代码,但我不认为它应该太难,它应该很好地扩展。请注意,它也适用于任何其他大小的子集,您可以使用不规则的n-gons为任何n平铺平面,尽管可能会变得困难。

    我想到的另一种方法是:

    1. 在一张大纸上画N点,其中N是字母表的大小。用字母表中的一个字母标记每个点。
    2. 连接任意n个点,其中n是所需子集的大小。那是你的第一个子集。
    3. 选择一个已连接的点,将其连接到(n-1)个未连接的点。那是你的下一个子集。
    4. 重复步骤3直到完成。
    5. 这需要更多的簿记,并且有许多需要处理的角落案例,但是再次编写代码并不困难。

      编辑:很容易将我的第一种方法转换为一种形式,这种形式更明显是图形上的算法。将每个子集建模为节点,并将字母表中的每个字母作为边缘。构造一个图,其中每个节点都有度n(子集中的元素数),每个字母(边)使用一次。

答案 4 :(得分:0)

@khuss

可以推广相同的方法。但它不是线性算法,可能是指数级的。

例如:当子集大小为4时,我们选择2对或更多对,其中包含4个唯一字符。

e.g。只有满足以下条件时,“AB和CD”或“AB,AC& AD”:

  1. 所有由4元组字符组成的对都可用。例如如果我们想用AB,AC& amp;然后AD然后所有的对A,B,C& D即AB,AC,AD,BC,BD,CD都必须可用。
  2. 如果满足条件1,那么我们形成ABCD并将C(4,2)= 6对标记为不可用。
  3. 我们继续像往常一样,直到不再形成4元组或者没有更多对可用。