查找有向图中的环

来源:互联网 发布:mac yosemite dmg下载 编辑:程序博客网 时间:2024/04/29 01:09
 

查找有向图中的环

分类: 算法 959人阅读 评论(1) 收藏 举报
算法listcomponentsdeletec

目录(?)[+]

部分引自http://blog.csdn.net/xw13106209/article/details/6538634

有向图:


主要有深度优先和拓扑排序2中方法

1、拓扑排序,如果能够用拓扑排序完成对图中所有节点的排序的话,就说明这个图中没有环,而如果不能完成,则说明有环。

2、可以用Strongly Connected Components来做,我们可以回忆一下强连通子图的概念,就是说对于一个图的某个子图,该子图中的任意u->v,必有v->u,则这是一个强连通子图。这个限定正好是环的概念。所以我想,通过寻找图的强连通子图的方法应该可以找出一个图中到底有没有环、有几个环。

3、就是用一个改进的DFS

    刚看到这个问题的时候,我想单纯用DFS就可以解决问题了。但细想一下,是不能够的。如果题目给出的是一个无向图,那么OK,DFS是可以解决的。但无向图得不出正确结果的。比如:A->B,A->C->B,我们用DFS来处理这个图,我们会得出它有环,但其实没有。

    我们可以对DFS稍加变化,来解决这个问题。解决的方法如下:

    图中的一个节点,根据其C[N]的值,有三种状态:

    0,此节点没有被访问过

    -1,被访问过至少1次,其后代节点正在被访问中

    1,其后代节点都被访问过。

    按照这样的假设,当按照DFS进行搜索时,碰到一个节点时有三种可能:

    1、如果C[V]=0,这是一个新的节点,不做处理

    2、如果C[V]=-1,说明是在访问该节点的后代的过程中访问到该节点本身,则图中有环。

    3、如果C[V]=1,类似于2的推导,没有环。    在程序中加上一些特殊的处理,即可以找出图中有几个环,并记录每个环的路径


无向图:

方法1:

  • 如果存在回路,则必存在一个子图,是一个环路。环路中所有顶点的度>=2。  
  • n算法:  

         第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度减一。  

         第二步:将度数变为1的顶点排入队列,并从该队列中取出一个顶点重复步骤一。  

         如果最后还有未删除顶点,则存在环,否则没有环。  

  • n算法分析:  

         由于有m条边,n个顶点。

         i)如果m>=n,则根据图论知识可直接判断存在环路。(证明:如果没有环路,则该图必然是k棵树 k>=1。根据树的性质,边的数目m = n-k。k>=1,所以:m<n)              

         ii)如果m<n 则按照上面的算法每删除一个度为0的顶点操作一次(最多n次),或每删除一个度为1的顶点(同时删一条边)操作一次(最多m次)。这两种操作的总数不会超过m+n。由于m<n,所以算法复杂度为O(n)。

  • 注:

         该方法,算法复杂度不止O(V),首先初始时刻统计所有顶点的度的时候,复杂度为(V + E),即使在后来的循环中E>=V,这样算法的复杂度也只能为O(V + E)。其次,在每次循环时,删除度为1的顶点,那么就必须将与这个顶点相连的点的度减一,并且执行delete node from list[list[node]],这里查找的复杂度为list[list[node]]的长度,只有这样才能保证当degree[i]=1时,list[i]里面只有一个点。这样最差的复杂度就为O(EV)了。

    方法2:

    DFS搜索图,图中的边只可能是树边或反向边,一旦发现反向边,则表明存在环。该算法的复杂度为O(V)。

    方法3:

    摘自:http://blog.csdn.net/lzrzhao/archive/2008/03/13/2175787.aspx

    PS:此方法于2011-6-12补充

    假定:图顶点个数为M,边条数为E

    遍历一遍,判断图分为几部分(假定为P部分,即图有 P 个连通分量)
    对于每一个连通分量,如果无环则只能是树,即:边数=结点数-1
    只要有一个满足      边数   >   结点数-1
    原图就有环
    将P个连通分量的不等式相加,就得到:
    P1:E1=M1-1
    P2:E2=M2-1
    ...
    PN:EN>MN-1
        所有边数(E)   >   所有结点数(M) - 连通分量个数(P)
    即:  E + P > M  所以只要判断结果  E  + P > M 就表示原图有环,否则无环.

    实例代码如下:


    如果要将有向图中的环输出:

    [cpp] view plaincopy
    1. bool Decoder::FindCycle(std::vector<vector<double> > &g, std::vector<int> &c)  
    2. {  
    3.     int size = g.size();  
    4.     vector<int> color(size,0);//所有的结点都没有被访问。当i结点为0,未被访问;i为-1,环;i为1,i的所有后裔结点都被访问过  
    5.     //for (int i=0;i<size;++i)  
    6.     for (int i= size -1;i>=0;--i)  
    7.     {  
    8.         if(color[i]==0)  
    9.         {  
    10.             color[i] = -1;  
    11.             if(Dfs(g,color,c,i))  
    12.             {  
    13.                 //c.push_back(i);  
    14.                 return true;  
    15.             }  
    16.         }  
    17.     }  
    18.     return false;  
    19. }  
    20.   
    21. bool Decoder::Dfs(std::vector<vector<double> > &g, std::vector<int> &color, std::vector<int> &c,int i)//如果有返回到i的环,则true;否则,false.遍历结点i的所有后继  
    22. {  
    23.     int size = g.size();  
    24.     for (int j=0;j<size;++j)  
    25.     {  
    26.         if (g[i][j] !=noEdge)  
    27.         {  
    28.             if(color[j]==0)  
    29.             {  
    30.                 color[j] = -1;  
    31.                 if(Dfs(g,color,c,j))  
    32.                 {  
    33.                     //c.push_back(j);  
    34.                     return true;  
    35.                 }  
    36.             }  
    37.             else if(color[j] == -1)  
    38.             {  
    39.                 c.push_back(j);  
    40.                 int start = j;  
    41.                 for (int ind = 0;ind <size ;++ind)//复杂度太高了,应该记录一个parent表  
    42.                 {  
    43.                     if(g[start][ind] !=noEdge && color[ind] == -1)  
    44.                     {  
    45.                         if(ind == j)  
    46.                             break;  
    47.                         c.push_back(ind);  
    48.                         start = ind;  
    49.                     }  
    50.                 }  
    51.                 return true;  
    52.             }  
    53.               
    54.         }  
    55.     }  
    56.     color[i] = 1;  
    57.     return false;  
    58. }  


    用拓扑排序查找有向图的环有如下的缺点

    http://hi.baidu.com/hpc_robot/blog/item/c21ade979489d86855fb96f2.html

  • 原创粉丝点击