是否有算法生成多集的所有唯一循环排列?

时间:2010-08-12 13:03:07

标签: algorithm permutation multiset necklaces

我在做一些热情的编程时遇到了这个问题。问题可以表述如下:

  

对于多集合A,让P(A)表示   A的所有可能排列的集合。   P(A)自然分为   不相交的子集是等价的   类,具有等价关系   “可以通过循环移位来关联”。列举所有   通过生成这些等价类   每个人中只有一个成员。

例如,考虑多集{0,1,1,2}。排列“0112”和“1201”是唯一的排列,但后者可以通过对前者进行循环移位来找到,反之亦然。所需的算法不应生成两者。

当然,蛮力方法是可行的:只需生成排列 - 无论循环重复 - 使用任何多集排列算法,并丢弃与先前结果相比较的重复。然而,这在实践中往往效率低下。如果不是零记账,所需的算法应该是最小的。

对这个问题的任何见解都深表感激。

5 个答案:

答案 0 :(得分:8)

答案 1 :(得分:1)

自下而上更容易:

如果A只包含1个元素,则P(A)也包含一个排列。 如果A只包含2个元素,则很容易看到相同的作品。

现在,让我们假设您已经拥有包含n个元素的A的所有P(A),并添加了一个元素。 它可以进入P(A)中任何排列的任何n个点。

我认为这个想法可以直接转换为您选择的语言中的递归算法,并希望我的解释足够清楚。

编辑:我知道我忽略了A可能包含重复元素的事实,但仍然在考虑那部分:)

就像 - 虽然如果你在开始排列算法之前对A进行排序,我认为这可能会消除重复。 (还在考虑这个问题)

答案 2 :(得分:0)

为了直观地理解这个问题,我想我们可以运用这个比喻。可视化墙上的时钟,但不是在面上有12个位置,它有n,其中n是集合中元素的数量。

然后每个等价类只是将A元素赋值给钟面上的一个位置。

一旦被指定,可以通过简单地旋转墙上的时钟来生成来自同一等价类的另一个排列。

要生成另一个不相关的A排列,您需要让一个元素跳过至少一个其他元素。

现在我看到的算法将是从作业开始,例如说我们在A = {a,b,c,d}中有四个元素,我们将它们分配到12,3,6和9个位置分别为视觉清晰度。然后我们的第一个操作是交换a和b。那么a和c,然后是a和d,然后我们将转到b并将其与3位置的元素交换,现在是c。

这样做直到我们达到d将产生所有等价类的代表。

这不会重复,但它应该比生成A的所有排列更有效。

答案 3 :(得分:0)

我想到的想法是,对于任何至少有一个元素只出现一次的集合,你可以将该元素放在列表的第一个位置以获得所有答案,然后生成其余部分的所有排列。数字。这是一个非常简单的解决方案,因为您的第一个元素是唯一的事实确保通过循环移动元素没有等价物。显然,您生成的所有解决方案都必须是唯一的。

显而易见的问题是,如果你没有单身元素,那么这就完全崩溃了。我把它放进去的主要原因是因为还有其他几个处理 no 重复的解决方案,我认为这个解决方案比它们更有效(解决了更多的情况)所以值得一提。在理解它的工作原理和实现方法方面,它也非常简单。我只希望我的理由是合理的。 ; - )

编辑进一步的想法:

我发现这个原则可以扩展到你在某种程度上有重复的情况。

如果您采用一个元素(我们现在假设重复),您可以只查看其排列以及哪些元素允许循环移位重复,如前所述,您可以“锁定”一个元素而不会失去一般性。例如,如果你总共有6个元素,并且A在这个集合中出现两次,那么你可以拥有:

AAXXXX,AXAXXX,AXXAXX,AXXXAX,AXXXXA

最后一个与第一个相同(在循环移位内),因此可以忽略,同样是第二个和第四个。第三个(AXXAXX)可以循环三次以恢复自身,因此具有循环潜力。前两个永远不会产生循环,无论你循环它们多少次,所以你分配剩余的元素,你只需要确保它们是唯一的分布,并保证你的循环结果是唯一的。

对于可以循环的第三个模式(AXXAXX),您需要查看元素B并重复这些过程。这次不幸的是,你将无法使用锁定第一个值的技巧来节省时间。

我不是百分之百确定如何将其变成一个完全正常运行的程序,但它有一些关于如何避免暴力的事情。

答案 4 :(得分:0)

我在这里提出了一个用python实现的解决方案

import itertools as it

L = ['a','b','c','d']
B = it.combinations(L,2)
swaplist = [e for e in B]
print 'List of elements to permute:' 
print swaplist
print
unique_necklaces = []
unique_necklaces.append(L)
for pair in swaplist:
    necklace = list(L)
    e1 = pair[0]
    e2 = pair[1]
    indexe1 = L.index(e1)
    indexe2 = L.index(e2)
    #swap
    necklace[indexe1],necklace[indexe2] = necklace[indexe2], necklace[indexe1]
    unique_necklaces.append(necklace)

for n in unique_necklaces:
    # Commented code display the rotation of the elements in each necklace
    print 'Necklaces'
    print n#, [n[-r:]+n[:-r]for r in (1,2,3)]   

这个想法是通过两个元素的排列来构建不同的项链。对于四个元素a,b,c,d的列表,算法产生:

['a', 'b', 'c', 'd']
['b', 'a', 'c', 'd']
['c', 'b', 'a', 'd']
['d', 'b', 'c', 'a']
['a', 'c', 'b', 'd']
['a', 'd', 'c', 'b']
['a', 'b', 'd', 'c']