【问题标题】:Grid Permutation Algorithm - Fixed Row Order网格置换算法 - 固定行顺序
【发布时间】:2012-04-21 06:22:45
【问题描述】:

想象一个 3x3 的网格:

[A, B, %]
[C, %, D]
[E, F, G]

百分比% 代表空白/位置。

行可以像串珠一样移动,这样第一行配置的排列可以是以下任何一个:

[A, B, %] or [A, %, B] or [%, A, B]

第二行也是如此。第三行不包含空槽,因此无法更改。

考虑到每一行的可能排列,我正在尝试生成所有可能的网格。

输出应产生以下网格:

[A, B, %]    [A, B, %]    [A, B, %]
[C, D, %]    [C, %, D]    [%, C, D]
[E, F, G]    [E, F, G]    [E, F, G]

[A, %, B]    [A, %, B]    [A, %, B]
[C, D, %]    [C, %, D]    [%, C, D]
[E, F, G]    [E, F, G]    [E, F, G]

[%, A, B]    [%, A, B]    [%, A, B]
[C, D, %]    [C, %, D]    [%, C, D]
[E, F, G]    [E, F, G]    [E, F, G]

我尝试了一种查看每一行并左右移动空间的方法,然后从中生成新的网格并递归。我将所有网格保存在一个集合中,并确保只生成尚未检查的位置以防止无限递归。

但是,我的算法似乎效率极低(~1s 排列!!)而且看起来也不是很好。我想知道是否有一种雄辩的方式来做到这一点?特别是在python中。

我有一些模糊的想法,但我确信有一种方法可以做到这一点,但我忽略了这一点。

编辑: 3x3 只是一个例子。网格可以是任何大小,真正重要的是行组合。例如:

[A, %, C]
[D, E, %, G]
[H, I]

也是一个有效的网格。

编辑 2: 字母必须保持顺序。例如 [A, %, B] != [B, %, A] 和 [B, A, %] 无效

【问题讨论】:

  • 这需要适用于任意大小的网格吗?
  • 是 ["A","B","%] 被认为是 != ["B","A","%"]?
  • 网格可以是任意大小,每行也可能有不同的长度。 3x3 只是一个例子。
  • 确实,["A","B","%] 被认为是 != ["B","A","%"]

标签: python algorithm permutation array-algorithms


【解决方案1】:

首先,您必须为每一行获取所有所需的排列。然后计算所有行的叉积。

可以通过使用字母 [A,B,%] 并改变起始索引来简单地计算行的排列:

import itertools
# Example: line = ['A','B','%']
def line_permutations(line):
   if '%' not in line:
       return [line]
   line.remove('%') # use copy.copy if you don't want to modify your matrix here
   return (line[:i] + ['%'] + line[i:] for i in range(len(line) + 1))

使用 itertools.product 最容易实现叉积

matrix = [['A','B','%'], ['C', '%', 'D'], ['E', 'F', 'G']]
permutations = itertools.product(*[line_permutations(line) for line in matrix])
for p in permutations:
    print(p)

此解决方案在内存和 CPU 要求方面是最佳的,因为永远不会重新计算排列。

示例输出:

(['%', 'A', 'B'], ['%', 'C', 'D'], ['E', 'F', 'G'])
(['%', 'A', 'B'], ['C', '%', 'D'], ['E', 'F', 'G'])
(['%', 'A', 'B'], ['C', 'D', '%'], ['E', 'F', 'G'])
(['A', '%', 'B'], ['%', 'C', 'D'], ['E', 'F', 'G'])
(['A', '%', 'B'], ['C', '%', 'D'], ['E', 'F', 'G'])
(['A', '%', 'B'], ['C', 'D', '%'], ['E', 'F', 'G'])
(['A', 'B', '%'], ['%', 'C', 'D'], ['E', 'F', 'G'])
(['A', 'B', '%'], ['C', '%', 'D'], ['E', 'F', 'G'])
(['A', 'B', '%'], ['C', 'D', '%'], ['E', 'F', 'G'])

【讨论】:

  • 我可能没有正确理解您,但仅更改起始索引不会授予所有排列。虽然它会提供所需的解决方案。
  • 你能在生成器中使用 return with argument(s) 语句吗?
  • @NeXuS:参见 OP“行可以像串珠一样移动”;我会调整它以使其更清晰。
  • @Abhijit 在达到产量之前它不是生成器。
  • @j13r:你确定吗?检查 result 在 Python 3 中运行它。
【解决方案2】:

定义一个叫做循环的函数

>>> def cycle(lst):
    while True:
        lst=lst[1:]+lst[0:1] if '%' in lst else lst
        yield lst
  • 给定一个迭代器,这将生成并返回一个循环左移。
  • 现在您必须将网格中的每一行传递给循环 与行长匹配的总迭代生成器
  • 现在使用 itertools.product 查找生成的所有组合 行循环组合。
  • 如果没有空槽,则不生成循环置换

最终结果如下

>>> for g in list(itertools.product(*[[x for (x,y) in zip(cycle(row),
           range(0,len(row) if '%' in row else 1))] for row in grid])):
    for r in g:
        print r
    print "="*10

对于您的网格,这将生成

['B', '%', 'A']
['%', 'D', 'C']
['E', 'F', 'G']
===============
['B', '%', 'A']
['D', 'C', '%']
['E', 'F', 'G']
===============
['B', '%', 'A']
['C', '%', 'D']
['E', 'F', 'G']
===============
['%', 'A', 'B']
['%', 'D', 'C']
['E', 'F', 'G']
===============
['%', 'A', 'B']
['D', 'C', '%']
['E', 'F', 'G']
===============
['%', 'A', 'B']
['C', '%', 'D']
['E', 'F', 'G']
===============
['A', 'B', '%']
['%', 'D', 'C']
['E', 'F', 'G']
===============
['A', 'B', '%']
['D', 'C', '%']
['E', 'F', 'G']
===============
['A', 'B', '%']
['C', '%', 'D']
['E', 'F', 'G']
===============

【讨论】:

    【解决方案3】:

    一个简单的实现:

    g=[['A', 'B', '%'],
    ['C', '%', 'D'],
    ['E', 'F', 'G']]
    
    from collections import deque
    from itertools import product
    
    def rotations(it):
        d = deque(it,len(it))
        for i in xrange(len(it)):
             d.rotate(1)
             yield list(d)
    
    for i in product(*[rotations(x) if '%' in x else [x] for x in g]):
        print i
    

    给予:

    (['%', 'A', 'B'], ['D', 'C', '%'], ['E', 'F', 'G'])
    (['%', 'A', 'B'], ['%', 'D', 'C'], ['E', 'F', 'G'])
    (['%', 'A', 'B'], ['C', '%', 'D'], ['E', 'F', 'G'])
    (['B', '%', 'A'], ['D', 'C', '%'], ['E', 'F', 'G'])
    (['B', '%', 'A'], ['%', 'D', 'C'], ['E', 'F', 'G'])
    (['B', '%', 'A'], ['C', '%', 'D'], ['E', 'F', 'G'])
    (['A', 'B', '%'], ['D', 'C', '%'], ['E', 'F', 'G'])
    (['A', 'B', '%'], ['%', 'D', 'C'], ['E', 'F', 'G'])
    (['A', 'B', '%'], ['C', '%', 'D'], ['E', 'F', 'G'])
    

    【讨论】:

    • 回溯(最近一次调用最后一次):文件“sandbox.py”,第 2 行,在 ['C', '%', 'D'] 类型错误:列表索引必须是整数, 不是元组
    • 忘了把逗号放在g :p
    【解决方案4】:

    来了。请注意,一方面这种方法不太干净,但它允许您仅计算一次 # len(matrix[0])-1 的排列并将它们用作输出的模板。

    from itertools import permutations,product
    
    def charPermutation(matrix):
        permutation_list=list(permutations(["%%"]+["%s"]*(len(matrix[0])-1))) #Compute once, use infinitely
        perms={i:[] for i in range(len(matrix))}
        for it,line in enumerate(matrix):
            chars=list(set(line)-set(["%"]))
            if sorted(line)==sorted(chars):
                perms[it]+=["".join([str(i) for i in line])]
            else:
                for p in permutation_list:
                    perms[it]+=["".join(["".join(p) % tuple(chars)])]
            perms[it]=list(set(perms[it]))
        return product(*[[list(k) for k in i] for i in perms.values()]) 
    
    g=[
       ["A", "B", "%"],
       ["C", "%", "D"],
       ["E", "F", "G"]]
    
    for x in charPermutation(g):
        print [i for i in x]
    
    [['A', '%', 'B'], ['C', 'D', '%'], ['E', 'F', 'G']]
    [['A', '%', 'B'], ['%', 'C', 'D'], ['E', 'F', 'G']]
    [['A', '%', 'B'], ['C', '%', 'D'], ['E', 'F', 'G']]
    [['%', 'A', 'B'], ['C', 'D', '%'], ['E', 'F', 'G']]
    [['%', 'A', 'B'], ['%', 'C', 'D'], ['E', 'F', 'G']]
    [['%', 'A', 'B'], ['C', '%', 'D'], ['E', 'F', 'G']]
    [['A', 'B', '%'], ['C', 'D', '%'], ['E', 'F', 'G']]
    [['A', 'B', '%'], ['%', 'C', 'D'], ['E', 'F', 'G']]
    [['A', 'B', '%'], ['C', '%', 'D'], ['E', 'F', 'G']]
    

    【讨论】:

    • 如果网格更大,比如 100*100 怎么办?我认为 OP 只是以 3X3 网格为例
    • 我通常发帖只是为了让人们了解其中的原因。如果他们能够实现他们真正需要的东西(并且如果他们能理解它),那就更好了。无论如何,这是微不足道的。
    • 这个输出是准确的,也是我需要的,但我不确定这是否可以缩放。我将编辑问题以明确 3x3 只是一个示例。
    • 最后……噗!它按比例缩放。 :P
    • @PeterHamilton 你能用一个大矩阵(> 15x15)对这个算法进行基准测试吗?
    猜你喜欢
    • 2014-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-17
    • 2021-01-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多