比较两个图表

时间:2013-04-04 18:49:33

标签: c++ algorithm data-structures graph

我需要比较许多图表(高达数百万的图表比较),我想知道最快的方法是什么。

图形的顶点最多可以有8个邻居/边,顶点的值可以是0或1.旋转图仍然是相同的图,每个图都有相同的顶点数。

图表可能如下所示:

graph example

现在我通过从第一个图形中取一个顶点并将其与第二个图形中的每个顶点进行比较来比较图形。如果我找到相同的顶点,那么我检查两个顶点的邻居是否相同,我重复这个,直到我知道图表是否相同。

这种方法太慢了。在不丢弃肯定不同的图形的情况下,将数千个图形与大约一百个顶点进行比较需要40多秒。

我在考虑计算每个图的唯一值,然后只比较值。我试图做到这一点,但我只设法得到的值如果相等则图表可能相等,如果值不同,那么图表也不同。
如果我的程序比较这些值,那么它会在大约2.5秒内计算所有内容(这仍然太慢)。

将顶点添加到此图并更新边缘的最佳/最快方法是什么?现在我将这个图存储在std::map< COORD, Vertex >中,因为我认为搜索顶点更容易/更快 COORD是游戏板上的顶点位置(顶点的位置与比较图形无关),Vertex是:

struct Vertex
{
    Player player; // Player is enum, FIRST = 0, SECOND = 1
    Vertex* neighbours[8];
};

此图表示Gomoku的当前电路板状态,电路板边缘和电路板尺寸为n * n,其中n最大为2 ^ 16。

我希望在写这篇文章时我没有犯过太多错误。我希望有人可以帮助我。

4 个答案:

答案 0 :(得分:3)

首先,您需要将每个图形转换为一致的表示,自然的方法是创建图形的有序表示。

第一级排序是通过根据邻居的数量进行分组来实现的。

然后通过将它们的邻居值(0和1)映射到二进制数来对具有相同数量的邻居的每组节点进行排序,然后使用该二进制数来强制执行组节点之间的顺序。

然后,您可以使用散列函数,该函数以有序形式迭代每个组的每个节点。然后可以使用散列值来提供加速查找

答案 1 :(得分:2)

您尝试解决的问题称为graph isomorphism

问题在于NP(虽然不知道它是否是NP-Complete)并且没有找到它的多项式时间算法。

您描述的算法似乎需要指数时间。

答案 2 :(得分:1)

我道歉,因为我还没有能力发表评论。这不是一个答案,而是一个可能的优化建议。

我建议尝试memoization(存储所有发现不同的顶点对),以便下次比较这两个顶点时,只需进行简单的查找和回复即可。这可能会改善性能(或使其恶化),具体取决于您拥有的图表类型。

答案 3 :(得分:0)

你已经发现自己检查同构可以通过检查一个bord来完成,其中所有n * n个移位乘以另一个的8个旋转,因此具有O(n^3)复杂度。

这可以减少到O(n^2)。让我们只在一个方向上移动,比如移动x轴。然后我们只需找到正确的y - 偏移量。为此,我们将两个图形的元素连接起来如下:

. . 1 .            0 . . 3
0 1 . .     =>     0 1 2 .     =>     0 3 0 1 2 0 2
. 0 . .            0 . 2 .
_______            
1 2 3 4            ^---- a 0 indicates start of a row

我们得到两个大小为n的数组,我们必须检查一个是否是另一个的循环排列。为此,我们将数组a与自身连接起来并搜索另一个。

例如,如果两个数组是a=0301202b=0203012,我们会使用KMP或类似内容在0203012中搜索03012020301202,这会在O(n + 2n)=O(n)时间内运行(我们可以摆脱整个预处理,因为第一个数组总是相同的。)

通过使用O(n)额外空间,将此n x-check与8 y-shift和O(n^2)轮次相结合,可以提高O(n)整体复杂度。< / p>