很久没写博客了(都怪做业太多,绝对不是我玩的太嗨了)算法
因此今天要写的是一个高大上的东西:强连通spa
首先,是一些强连通相关的定义 //来自度娘3d
1.强连通图(Strongly Connected Graph)是指在有向图G中,若是对于每一对vi、vj,vi≠vj,从vi到vj和从vj到vi都存在路径,则称G是强连通图。code
2.有向图的极大强连通子图,称为强连通份量(strongly connected components)。component
固然,看定义是确定看不懂的,因此,我举个栗子说明一下blog
咱们如下图为例,这是一个特别经典的强连通图,三个被框起来的地方就分别是三个强连通份量get
咱们DFS一下,从一出发,咱们从右至左遍历,因此路径即是1——>3——>5——>6,到了6,咱们发现无路可走了,就回到5,而6不能到达任何一个点,因此它独自为一个强连通份量。同理,5也是一个强连通份量。而1——>3——>4——>1——>2,能够互相到达,因此这又是一个强连通份量。博客
Tarjan算法it
接下来,就是一个在强连通中,经常使用的一个算法。io
Tarjan算法是基于对图深度优先搜索的算法,每一个强连通份量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时能够判断栈顶到栈中的节点是否为一个强连通份量。
定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树可以追溯到的最先的栈中节点的次序号。
当DFN(u)=Low(u)时,以u为根的搜索子树上全部节点是一个强连通份量。
接下来演示一下算法:
从1开始DFS,把遍历到的节点加入栈中。搜索到节点u=6时,DFN[6]=LOW[6],找到了一个强连通份量。退栈到u=v为止,{6}为一个强连通份量。
返回到5,发现DFN[5]=LOW[5],退栈后{5}为一个强连通份量。
继续回到1,最后访问2。访问边(2,4),4还在栈中,因此LOW[2]=DFN[4]=5。返回1后,发现DFN[1]=LOW[1],把栈中节点所有取出,组成一个连通份量{1,3,4,2}。
因此,三个强连通份量所有都找出来了。
模板以下:
1 void Tarjan(int u){ 2 dfn[u]=low[u]=++num; 3 st[++top]=u; 4 for (int i=fir[u]; i; i=nex[i]){ 5 int v=to[i]; 6 if (!dfn[v]){ 7 Tarjan(v); 8 low[u]=min(low[u],low[v]); 9 } 10 else if (!co[v]) 11 low[u]=min(low[u],dfn[v]); 12 } 13 if (low[u] == dfn[u]){ 14 co[u]=++col; 15 while (st[top]!=u){ 16 co[st[top]]=col; 17 --top; 18 } 19 --top; 20 } 21 }