找到同构置换集的算法

时间:2015-05-11 18:39:01

标签: c++ c arrays algorithm permutation

我有一组排列,我想删除同构排列。

  

我们有S组排列,其中每组包含K个排列,每个排列都表示为N个元素的数组。我目前正在将其另存为数组int pset[S][K][N],其中SKN是固定的,而N大于K.

     

两组排列AB同构,如果存在排列P,则转换来自A的元素到B(例如,如果a是集A的元素,则P(a)是集合B的元素。在这种情况下,我们可以说 P使AB同构

我目前的算法是:

  1. 我们选择所有对s1 = pset[i]s2 = pset[j],以便i < j
  2. 选择集(s1s2)中的每个元素都是从1K的。这意味着每个元素都可以表示为s1[i]s2[i],其中0 < i < K+1
  3. 对于T元素的每个排列K,我们执行以下操作:
    • 找到排列R,以便R(s1[1]) = s2[1]
    • 检查R是否是使s1T(s2)同构的排列,其中T(s2)是对s2的元素(排列)的重新排列},基本上我们只检查R(s1[i]) = s2[T[i]]0 < i < K+1
    • 如果没有,那么我们转到下一个排列T
  4. 这种算法效果很慢:O(S^2)用于第一步,O(K!)循环遍历每个排列TO(N^2)以找到R,以及O(K*N)来检查R是否是使s1s2同构的排列 - 所以它是O(S^2 * K! * N^2)

      

    问题:我们可以加快速度吗?

5 个答案:

答案 0 :(得分:6)

您可以进行排序和比较:

// 1 - sort each set of permutation
for i = 0 to S-1
    sort(pset[i])
// 2 - sort the array of permutations itself
sort(pset)
// 3 - compare
for i = 1 to S-1 {
    if(areEqual(pset[i], pset[i-1]))
        // pset[i] and pset[i-1] are isomorphic
}

一个具体的例子:

0: [[1,2,3],[3,2,1]]
1: [[2,3,1],[1,3,2]]
2: [[1,2,3],[2,3,1]]
3: [[3,2,1],[1,2,3]]

1:

之后
0: [[1,2,3],[3,2,1]]
1: [[1,3,2],[2,3,1]] // order changed
2: [[1,2,3],[2,3,1]]
3: [[1,2,3],[3,2,1]] // order changed

2之后:

2: [[1,2,3],[2,3,1]]
0: [[1,2,3],[3,2,1]]
3: [[1,2,3],[3,2,1]] 
1: [[1,3,2],[2,3,1]]

3之后:

(2, 0) not isomorphic 
(0, 3) isomorphic
(3, 1) not isomorphic

复杂性怎么样?

  • 1是O(S * (K * N) * log(K * N))
  • 2是O(S * K * N * log(S * K * N))
  • 3是O(S * K * N)

因此整体复杂度为O(S * K * N log(S * K * N))

答案 1 :(得分:5)

有一个非常简单的解决方案:换位。

如果两个集是同构的,则表示存在一对一映射,其中集i中索引S1处的所有数字的集合等于某些集合中的所有数字的集合集合k中的索引S2。我的猜想是没有两个非同构集具有这种属性。

(1)Jean Logeart的例子:

0: [[1,2,3],[3,2,1]]
1: [[2,3,1],[1,3,2]]
2: [[1,2,3],[2,3,1]]
3: [[3,2,1],[1,2,3]]

Perform ONE pass:

Transpose, O(n):
0: [[1,3],[2,2],[3,1]]

Sort both in and between groups, O(something log something):
0: [[1,3],[1,3],[2,2]]

Hash:
"131322" -> 0

...
"121233" -> 1
"121323" -> 2
"131322" -> already hashed.

0 and 3 are isomorphic.

(2)vsoftco在对Jean Logeart的回答中的反例:

A = [ [0, 1, 2], [2, 0, 1] ]
B = [ [1, 0, 2], [0, 2, 1] ]

"010212" -> A
"010212" -> already hashed.

A and B are isomorphic.

您可以将每个集合转换为转置排序的字符串或散列或任何压缩对象,以进行线性时间比较。请注意,即使一个AB转换为C而另一个p,此算法也会将所有三个集ABp视为同构。 {1}}将A转换为C。显然,在这种情况下,有p个将这三个集合中的任何一个转换为另一个集合,因为我们所做的只是将一个集合中的每个i移动到特定的k在另一个。如果你正如你所说,你的目标是去除同构排列,&#34;你仍然会得到要删除的集合列表。

说明:

假设与我们的排序哈希一起,我们保留了每个i来自哪个排列的记录。 vsoftco的反例:

010212  // hash for A and B
100110  // origin permutation, set A
100110  // origin permutation, set B

为了确认同构,我们需要显示第一组中每个索引中分组的i被移动到第二组中的某些索引,指数没关系。对i组进行排序不会使解决方案无效,而是用于确认集合之间的移动/置换。

现在根据定义,散列中的每个数字和散列中每个组中的每个数字在每个集合中的原始排列中恰好表示一次。但是,我们选择在散列中的每个i组中排列数字,我们保证该组中的每个数字代表集合中的不同排列;当我们理论上分配这个数字时,我们保证它是&#34;保留&#34;仅适用于那种排列和索引。对于给定的数字,比如2,在两个哈希中,我们保证它来自集合A中的一个索引和置换,而第二个哈希对应于集合{中的一个索引和置换{ {1}}。这就是我们真正需要展示的 - 一个集合中的每个排列的一个索引中的数字(一组不同的B&#39;)仅转到一个索引另一组(一组不同的i&#39; s)。这个数字所属的排列和索引是无关紧要的。

请注意,可以使用一个排列函数或应用于k&的不同排列函数的各种组合,从S2派生任何与S1同构的集S1 #39;成员。我们的数字和组实际表示的排序或重新排序是我们选择作为同构的解决方案而不是实际分配哪个数字来自哪个索引和排列的排列。这是vsoftco的反例再次,这次我们将添加哈希的原始索引:

S1

因此我们permutation是同构的解决方案:

enter image description here

或者,按顺序:

enter image description here

(请注意,在Jean Logeart的例子中,同构的解决方案不止一个。)

答案 2 :(得分:4)

Diagnosis.findAll中取a0。然后找到它的反向(快速,A),将其称为O(N)。然后在a0inv中选择一些i并定义B并检查P_i = b_i * ainv生成P_i * aBa不同。对B中的每个A执行此操作。如果您找不到该关系所包含的任何i,则这些集不是同构的。如果您找到这样的i,则这些集是同构的。对于它检查的每对集合,运行时为i,并且您需要检查O(K^2)集,因此最终会得到O(S^2)

PS:我在这里假设通过&#34; 映射A到B &#34;你的意思是在排列组合下进行映射,因此O(S^2 * K^2 * N)实际上是由排列P(a)组成的排列P,并且我使用了a是{a}}排列,然后必须存在P i Pa = b_i。{/ p>

编辑我决定取消删除我的答案,因为我不相信基于搜索的前一个(@Jean Logeart)是正确的。如果是的话,我很乐意删除我的,因为它表现得更糟,但我想我有一个反例,请参阅以下评论,让我们回答。

答案 3 :(得分:4)

假设 s1中的两个元素,S 中的s2 \是同构的。然后,如果 p1 p2 是排列,则 s1 s2 同构,iff p1(s1) p2(s2)同构,其中 pi(si)是通过将 pi 应用于每个元素而获得的排列集合 SI

对于每个 i in 1 ... s j in 1 ... k ,选择 j-th 成员< em> si ,找到将其变为统一的排列。将其应用于 si 的所有元素。将 k 排列中的每一个散列为一个数字,获取 k 数字,以便选择 i j ,成本 nk

比较 i j 的两个不同值的散列集是 k ^ 2&lt; NK 。因此,您可以找到成本 s ^ 2 k ^ 3 n 的候选匹配集。如果实际匹配数量较少,则总体复杂程度远低于您在问题中指定的范围。

答案 4 :(得分:2)

要检查两组 S 1 S 2 是否同构,您可以进行更短的搜索。

如果它们是同构的,那么有一个排列 t S 1 的每个元素映射到 S 2 的元素;找到 t 你可以选择 S 1 的任何固定元素 p 并考虑排列

 t₁ = (1/p) q₁
 t₂ = (1/p) q₂
 t₃ = (1/p) q₃
 ...

S 2 的所有元素 q 。因为,如果存在有效的 t ,那么它必须将元素 p 映射到 S 2 的元素,因此只有映射 p <的排列/ strong>对 S 2 的元素是可能的候选者。

此外,如果候选人 t 检查两组排列 S 1 S 2 是否相等,则可以使用计算的哈希作为x - 或者每个元素的哈希码,只有在哈希匹配时才对所有排列进行全面检查。