摘要: 转载请注明来自stanlysheng——talk is cheap, show me your code。http://www.cnblogs.com/stanly/ 。谢谢。此文我也在CSDN发过。

最近在学习子图同构算法。什么是子图同构,看这里-->图论。在图论的维基百科中有子图同构的描述。

子图同构一直是图论中比较重要的一个问题,经过各位大牛长时间的学习和研究,发现求解子图同构是一个NP完全问题。什么是NP完全问题,可以戳这里--->NP完全

在经过不断地搜索和阅读论文,发现了不少论文都在讨论子图同构算法。出现得比较多并且很多人都知道并认可的,有这么几种算法:Ullmann算法、Nauty算法、SD算法、VF算法以及在VF算法上进行改进的VF2算法。其中Ullmann算法应该是最早提出的可以找到子图同构的算法。因此现在学习图论如果设计到同构,虽然不会用ullmann算法,但是一般都会以其作为对子图同构的基础进行了解和学习。中间三种算法尚未研究,以后可能会看,因为时间和研究原因我的重点在第一个ullmann和最后的公认最好的VF2算法。

在最坏情况下,ullmann算法的时间复杂度与图中节点数目的指数成正比。ullmann算法以深度优先的方式进行搜索,搜索过程表示为一个布尔矩阵。当节点不匹配时则回溯到最近匹配的节点,寻找其他的搜索方向。同时,算法还会检查匹配点对的邻接点的匹配情况,尽可能早的识别出不可匹配的节点。提高算法的效率。

先介绍深度优先的简单穷举方法,这个阶段不包含上面说的检查匹配点对的邻接点的匹配情况(即refine procedure),将在后面我写好代码之后再发。

此搜索方法其实是深度优先遍历两图的关联矩阵,来找到满足其子图同构的关联矩阵。

对于给定的两个图,是从节点数目大的那个图中寻找部分节点和边,和节点数目小的图是同构的。

图G1=<V1,E1>,G2=<V1,E1>,G1 和G2 的节点数分别为p1和p2。他们的邻接矩阵表示分别为A=[aij]和B=[bij]。

该算法要寻找的同构关系表现为寻找两图的一个关联矩阵M,这是一个p1*p2的矩阵,其元素mij表示G1的第 i 个节点和G2的第 j 个节点是否对应。因此这个矩阵的限制为:每行只有一个1,而每列最多只有一个1 。因此mij==1表示G1的第 i 个节点和G2的第 j 个节点对应。否则不对应。

条件(1)判定:当找到这样一个M`的时候我们进行如下操作得到另一个p1*p1的矩阵C,定义C为:C=M`(M`B)T,后面的T表示(M`B)做转置。即M`乘以[(M`B)的转置]得到C,如果对于每一个i , j 都属于(1,p1)都满足当aij == 1 时 有cij == 1。那么我们就称此时的矩阵M`标识了G1 到G2子图的一个同构。

初始化M的时候,遵循下面的原则:

如果G2的第 j 个节点的度大于或者等于G1的第 i 个节点的度(表示可能匹配但是不一定),则mij = 1。否则等于0。(此原则是针对无向图,如果是对于有向图则有出度和入度均要大于等于,对于节点可能有其他属性的情况也是类似,保证G2的属性或者条件强于G1即可)。

所以深度优先搜索的就是将M0深度遍历找到所有的满足条件(1)判定的矩阵。

深度优先搜索中,使用d来表示搜索中的层(第几行),使用一个大小为p2的向量F{F1,F2,…F(x)…,F(p2)}(数组表示)来表示哪一列被使用了。比如F[2]==1表示在搜索中第二列被使用了,如果F[2]==0则表示没被使用。同样还使用一个大小为p1的向量H{H1,H2,……,H(p1)}来表示在哪一层使用了哪一列。H[d] = k表示在层d中使用了第k列。

除此之外,还需要一个三维矩阵来记录每层变化过的M`,保证回溯的时候可以回到上一层。第一维长度和d大小一样。二维三维即为M的维度。

Ullmann算法的提出者Ullmann的论文,比较早论文写得挺难懂的。他的伪代码有些需要改动。伪代码如下:

step1     

construct  M0,M=M0,d=0, H[0] = 0;

for element in F set element = 0

if  m has a row that all zero  return; (这一步可以放在refine里面)

 

step2     

if there are no value of j such  that  m[d][j] && F[j] = 0  then goto step7

matrixlist[d] = M

if d = 0 then k = H[0] else k = 0

 

step3      

if  matrixlist[d][d][k] = 0 or F[k] == 1

then  if k < p2-1 then k+=1 and goto step3 else goto step7

else  for all j != k set m[d][j] = 0;

 

step4      if d < p1 then goto step6 else   ( H[d] = k and use condition(1) and giveoutput if an isomorphism is found )

 

step5     

if there is no j > k such that m[d][j] = 1 and F[j] = 0 then k += 1 and  goto step7

else k += 1 and goto step3

 

step6    

 H[d] = k

F[k] = 1

d +=1

goto step2

 

step7     

if d ==0 then terminate algorithm

if k < p2-1 then copy matrixlist[d]  to M and goto step5

else  d= d-1     k = H[d]    F[k]=0 copy matrixlist[d]  to M and goto step5

以上就是算法程序的伪代码。具体实现还是需要自己动手。主要流程就是这样的,缺少的就是condition(1)的判断(包含矩阵的转置和两矩阵的乘法)。很简单,自己加上。之后学习完refine procedure之后会再加上。暂时就这么多。

国内真心很少有这个问题的资料,一些论文都是应用子图同构算法,极少有详细讲这些算法的。

摘要: 转载请注明来自stanlysheng——talk is cheap, show me your code。http://www.cnblogs.com/stanly/ 。谢谢。

posted on 2013-10-02 22:53  stanlysheng  阅读(3714)  评论(2编辑  收藏  举报