tarjan有向图的强连通
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了tarjan有向图的强连通相关的知识,希望对你有一定的参考价值。
强连通:在有向图G中,两个顶点间至少存在一条路径,则两个点强连通。
强连通图:在有向图中,每两个顶点都强连通,则有向图G就是一个强连通图。
强连通分量:在非强连通图中的极大强连通子图,就称为强连通分量。
直接根据定义,可以通过双向遍历取交集的方法求强连通分量,但是其复杂度为O(N^2+M)。更好的方法是用tarjan算法,其时间复杂度为O(N+M)。
tarjan:其实就是对图的深度优先遍历。
算法模拟:
定义 DFN [u]为节点u被搜索到时的次序编号(也就是所遍历的第几个);
定义LOW[U]为U或者U 的子数能够追溯到最早的栈中节点的次序号。
(当DFN[U] == LOE[U] 时,以U为根的搜索子树上所有节点是一个强连通分量。实质上就是这个点的整个子树回溯完了,没有链接的路了)
此时的F点DNF[F]==LOW[F]=4,所以F为一个强连通分量,只有它自己本身。
然后返回节点E,此时发现 DFN[E] == LOW[E] =5,所以E也单独为一个强连通分量,只有他本身。
然后返回节点C:
从C节点继续搜其他的C的子树,搜到节点D,将D加入栈中。然后D有 D -> F ,但是F 已经出栈,所以F节点直接跳过,
还有一个节点A , 但是呢,A节点已经在栈中,所以LOW[D] = DFN[A] = 1,然后是一个回溯的过程,所以呢,LOW[C] = LOW [D] =1;
所以说明这三个节点已经是一个强连通分量了。
继续回到节点A,最后访问B节点,,然后 B-> D ,然而 D点还在栈中,所以LOW[B] = DFN [ D ] = 5 ,DFN[B] = 6 ;
没有其他点了,算法结束,最后得到 {A,B,C,D} ,{E}, {F}为强连通分量。
在tarjan算法中,每个点只被访问了一次,而且只进行了一次的栈,每条边也只被访问了一次,。所以该算法的时间复杂度为O(N+M);
程序模板:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 6 #define N 100 7 #define M 100 8 9 struct node 10 { 11 int v; 12 int next; 13 }; 14 15 node edge[M];//边的集合 16 17 int a[N];//顶点的集合 18 int instack[N];//模拟栈,标记是否在栈中 19 int stack[N]; 20 int belong[N];//各个顶点属于哪个强连通分量 21 int DFN[N]; 22 int LOW[N];//栈中能够追溯到最早的节点序号 23 int n;//点的个数 24 int m;//边的个数 25 int count;//边的计数器 26 int index;//序号(时间戳) 27 int top; 28 int sun;//强连通分量的个数 29 30 //用邻接表存储 31 void add_edge(int u,int v) 32 { 33 edge[count].next=a[u]; 34 edge[count].v=v; 35 a[u]=count++; 36 } 37 38 void tarjan(int u) 39 { 40 int i,j; 41 int v; 42 DFN[u]=LOW[u]=++index; 43 instack[u]=true; 44 stack[++top]=u;//进栈 45 for(i=a[u];i!=-1;i=edge[i].next) 46 { 47 v=edge[i].v; 48 if(!DFN[v])//如果DFN[v]为0,没被访问 49 { 50 tarjan(v); 51 //一个回溯的过程 52 if(LOW[v]<LOW[u]) 53 LOW[u]=LOW[v]; 54 } 55 else 56 { 57 if(instack[v]&&DFN[v]<LOW[u]) 58 LOW[u]=DFN[v]; 59 } 60 } 61 if(DFN[u]==LOW[u]) 62 { 63 sun++; 64 //出栈 65 do 66 { 67 j=stack[top--]; 68 instack[j]=false; 69 belong[j]=sun; 70 }while(j!=u); 71 72 } 73 } 74 75 void solve() 76 { 77 int i; 78 top=index=sun=0; 79 memset(DFN,0,sizeof(DFN)); 80 memset(LOW,0,sizeof(LOW)); 81 for(i=1;i<=n;i++) 82 { 83 if(!DFN[i]) 84 tarjan(i); 85 } 86 } 87 88 int main() 89 { 90 int i,j,k; 91 count=0; 92 memset(a,-1,sizeof(a)); 93 scanf("%d %d",&n,&m); 94 for(i=1;i<=m;i++) 95 { 96 scanf("%d %d",&j,&k); 97 add_edge(j,k); 98 } 99 solve(); 100 for(i=1;i<=n;i++) 101 printf("%d ",belong[i]); 102 }
以上是关于tarjan有向图的强连通的主要内容,如果未能解决你的问题,请参考以下文章