我有一组排列,我想删除同构排列。
我们有
S
组排列,其中每组包含K
个排列,每个排列都表示为N
个元素的数组。我目前正在将其另存为数组int pset[S][K][N]
,其中S
,K
和N
是固定的,而N大于K.两组排列
A
和B
是同构,如果存在排列P
,则转换来自A
的元素到B
(例如,如果a
是集A
的元素,则P(a)
是集合B
的元素。在这种情况下,我们可以说P
使A
和B
同构。
我目前的算法是:
s1 = pset[i]
和s2 = pset[j]
,以便i < j
s1
和s2
)中的每个元素都是从1
到K
的。这意味着每个元素都可以表示为s1[i]
或s2[i]
,其中0 < i < K+1
T
元素的每个排列K
,我们执行以下操作:
R
,以便R(s1[1]) = s2[1]
R
是否是使s1
和T(s2)
同构的排列,其中T(s2)
是对s2
的元素(排列)的重新排列},基本上我们只检查R(s1[i]) = s2[T[i]]
,0 < i < K+1
T
。这种算法效果很慢:O(S^2)
用于第一步,O(K!)
循环遍历每个排列T
,O(N^2)
以找到R
,以及O(K*N)
来检查R
是否是使s1
和s2
同构的排列 - 所以它是O(S^2 * K! * N^2)
。
问题:我们可以加快速度吗?
答案 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
O(S * (K * N) * log(K * N))
O(S * K * N * log(S * K * N))
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.
您可以将每个集合转换为转置排序的字符串或散列或任何压缩对象,以进行线性时间比较。请注意,即使一个A
将B
转换为C
而另一个p
,此算法也会将所有三个集A
,B
和p
视为同构。 {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是同构的解决方案:
或者,按顺序:
(请注意,在Jean Logeart的例子中,同构的解决方案不止一个。)
答案 2 :(得分:4)
在Diagnosis.findAll
中取a0
。然后找到它的反向(快速,A
),将其称为O(N)
。然后在a0inv
中选择一些i
并定义B
并检查P_i = b_i * ainv
生成P_i * a
,B
与a
不同。对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 - 或者每个元素的哈希码,只有在哈希匹配时才对所有排列进行全面检查。