python:查找集合的所有拉丁方(或具有较少列的部分正方形)

时间:2015-03-16 03:00:37

标签: python algorithm permutation combinatorics

编辑:
感谢评论者道格拉斯·扎尔(Douglas Zare),我已经将这篇文章的标题重新命名为更合适的术语,以供其他可能正在寻找类似内容的人使用。以下David Eisenstat的代码非常有用。


原始邮件:
我为缺乏合适的集合理论术语而道歉...但我在这里有点超出我的深度(虽然我怀疑这是一个容易的问题)。我正在尝试开发一种算法,它将接受一个集合和一个数字K,并返回所有可能的“完整”分区,其中包含K大小的子集和set coverage = K,以便:

  1. 任何给定的子集都不会有重复
  2. 在所有子集中合并第n个术语,为集合提供了完整的分区
  3. 所有子集的第n个项在其余子集中都是唯一的
  4. 例如:

    function({A, B, C, D}, 2)
    

    应该返回所有可能的集合:

    [AB, BC, CD, DA]
    [AB, BD, CA, DC]
    [AC, BD, CA, DB]
    [AD, DA, CB, BC]
    [BC, CA, DB, AD]
    ...
    

    另外,为了它的价值

    1. 单个子集中元素的顺序无关紧要(只要遵守其他三个规则
    2. 所以以下内容是等效的:

      [AB, BA, CD, DC] = [BA, AB, DC, CD] = [AB, BA, DC, CD] = [BA, AB, CD, DC]
      

      1. 各种子集的顺序很重要
      2. 所以以下是不同的:

        [BC, CA, DB, AD] ≠ [CA, BC, AD, DB]
        

        换句话说,用矩阵术语:我正在查找包含rows=len(set)columns=K的所有矩阵,因此每列都有精确的封面,任何行都不会出现多次。

        function({A, B, C, D}, 3)
        

        将返回所有矩阵,如下所示......

        ABC      ADB    
        BCD      DCA    
        CDA      CBD    
        DAB      BAC 
        

        我希望在python中得到一个答案,使用像numpy这样的库很好......但只是一般的算法策略也会受到赞赏。我认为像Algorithm X这样的东西可能会派上用场......但是我无法从那里跳到这里概述的问题......

1 个答案:

答案 0 :(得分:0)

可以进行回溯搜索。 Python 3:

import itertools
import operator


def valid(cols_so_far):
    for i, col1 in enumerate(cols_so_far):
        for col2 in cols_so_far[i + 1:]:
            if any(map(operator.eq, col1, col2)):
                return False
    return True


def enum(letters, k, cols_so_far=None):
    if cols_so_far is None:
        cols_so_far = (tuple(letters),)
    if not valid(cols_so_far):
        pass
    elif len(cols_so_far) == k:
        yield tuple(zip(*cols_so_far))  # transpose
    else:
        for perm in itertools.permutations(letters):
            yield from enum(letters, k, cols_so_far + (perm,))