当前位置: 首页 > 知识库问答 >
问题:

寻找同构置换集的算法

太叔富
2023-03-14

我有一组排列的数组,我想移除同构排列。

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

如果存在将元素从< code>A转换为< code>B的置换< code>P,则两组置换< code>A和< code>B是同构的(例如,如果< code>a是集合< code>A的元素,则< code>P(a)是集合< code>B的元素)。在这种情况下,我们可以说< code>P使得< code>A和< code>B同构。

我目前的算法是:

    < li >我们选择所有对< code>s1 = pset[i]和< code>s2 = pset[j],因此< code>i

这个算法的工作速度非常慢:O(S^2)是第一步,O(K!)循环遍历每个排列TO(N^2)找到RO(K*N)检查R是否是使s1s2同构的排列 - 所以它是O(S^2 * K! * N^2)。

问题:我们能让它更快吗?

共有3个答案

拓拔霄
2023-03-14

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

对于 1...s 中的每个 i 和 1...k 中的每个 i,选择 si 的第 j 个成员,并找到将其更改为单位的排列。将其应用于 si 的所有元素。将每个 k 排列散列为一个数字,得到 k 个数字,用于 i 和 j 的任何选择,成本为 nk。

比较I和j的两个不同值的散列集合是k^2

井斌斌
2023-03-14

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

如果两个集合是同构的,则意味着存在一对一映射,其中集合 S1 中索引 i 处的所有数字的集合等于集合 S2 中某个索引 k 处的所有数字的集合。我的猜想是,没有两个非同构集合具有此性质。

(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.

您可以将每个集合转换为转置排序字符串或哈希或任何压缩对象,以进行线性时间比较。请注意,该算法将所有三个集合ABC视为同构,即使一个pA转换为B,另一个pA转换为C。显然,在这种情况下,有ps将这三个集合中的任何一个转换为另一个,因为我们所做的是将一个集合中每个i移动到另一个集合的特定k。如您所述,如果您的目标是“移除同构排列”,您仍然会得到一个要移除的集合列表。

说明:

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

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

为了确认同构,我们需要证明从第一个集合到每个索引分组的i移动到第二个集合中的某个索引,哪个索引无关紧要。对 i 的组进行排序不会使解失效,而是用于确认集合之间的移动/排列。

现在根据定义,散列中的每个数和散列中每个组中的每个数在原点排列中对于每个集合仅被表示一次。然而,我们选择在散列中排列每组< code>i中的数字,我们保证该组中的每个数字代表集合中的不同排列;当我们从理论上分配这个数字时,我们保证它只为那个排列和索引“保留”。对于给定的数,比如说< code>2,在两个散列中,我们保证它来自集合< code>A中的一个索引和置换,并且在第二个散列中对应于集合< code>B中的一个索引和置换。这就是我们真正需要展示的——一个集合(一组不同的< code>i)中的每个排列的一个索引中的数字只到另一个集合(一组不同的< code>k)中的一个索引。数字属于哪个排列和索引无关紧要。

请记住,与setS1同构的任何集合S2都可以使用一个置换函数或应用于S1成员的不同置换函数的各种组合从S1派生出来。我们的数字和组的排序或重新排序实际上代表的是我们选择分配的置换作为同构的解决方案,而不是实际分配哪个数字来自哪个索引和置换。这又是vsoftco的反例,这次我们将添加哈希的原始索引:

110022 // origin index set A
001122 // origin index set B

因此,我们的排列,同构的解决方案,是:

或者,按顺序:

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

宰父才
2023-03-14

您可以排序和比较:

// 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))

 类似资料:
  • 问题内容: 假设我在一行中有一些随机的文本块。像这样 但是无论出于何种原因(包含元素的宽度设置,使用文本缩放等),在查看器的屏幕上它都显示为两行或更多行。 要么 有没有办法通过JavaScript找出发生换行的地方? 并返回而不管文本如何显示。 问题答案: 这就是我最终使用的(随意批评和复制以作恶用)。 首先,当编辑来自用户时,将其拆分为。 替换换行的原因是,编辑文本框中填充了,它会忽略标签,但出

  • 假设我有一个无向多图,即一个(G,E)对,其中G是一个有限的结点集,E是一个有限的边集。我正在寻找一个算法,将分配一个单一的字符串值到每个节点在以下的约束。 1. 每个节点都被赋予一组约束(可能是空的),这些约束限制了允许的值。我希望至少支持以下类型的值约束: null 有两种类型的边缘: 不同, 相同, 这意味着应该为相关节点分配不同/相同的值(意味着不相等/相等的字符串)。 null 这意味着

  • 我正在做一个个人项目,试图找到一个人的长相,因为数据库中有其他人的照片,所有照片都是以一致的方式拍摄的——人们直视相机,表情中立,不歪头(想想护照照片)。 我有一个系统,用于在人脸上放置二维坐标的标记,我想知道是否有任何已知的方法可以在这种方法下找到一张相似的脸? 我找到了以下面部识别算法:http://www.face-rec.org/algorithms/ 但是,没有一个专门负责寻找相貌相似的

  • 问题内容: 实际上,我有2个表Friends表和users表,我想要达到的目的是通过检查另一个用户的朋友来获取我的共同朋友,并从users表中获取这些共同朋友的数据 表的朋友是这样建立的 然后表格数据看起来像这样 然后假设我是ID为2的用户,那么在该表中我有3个朋友-1、3和4。我要检索的是与用户1相同的朋友,他们也有3个朋友-2、3和4。并从表用户中检索2个共同的共同朋友3和4的数据 问题答案:

  • 我试图在Ubuntu 12.04(x86\u 64 GNU/Linux)上运行一个Java应用程序,该应用程序使用Eclipse Luna中的SWT库。 我收到此错误: Java HotSpot(TM)64位服务器VM警告:您已加载library/home/saeed/。swt/lib/linux/x86_64/libswt-gtk-4427。所以这可能会禁用堆栈保护。VM现在将尝试修复堆栈保护。

  • 我正在尝试用Java开发游戏《奥赛罗》,我正在努力寻找玩家可用的动作(而不是电脑)。 比如我是玩家1,我在玩白色的棋子, 检查按钮是否是空的。(我使用按钮作为瓷砖) 检查是否有相反颜色的邻居。 如果有,继续检查每个方向有相反的颜色,直到 如果我们到达边界-返回false. 如果我们达到我们的颜色-把所有的碎片变成我的颜色。 我在努力实现3。五,。 我如何迭代通过所有的方向(最大的8个方向,如果我在