TARJAN 算法求强连通分量
在有向图G中,如果两个顶点间至少存在一条路径,称两个顶点强连通(strongly connected)。如果有向图G的每两个顶点都强连通,称G是一个强连通图。非强连通图有向图的极大强连通子图,称为强连通分量(strongly connected components)。
下图中,子图{1,2,3,4}为一个强连通分量,因为顶点1,2,3,4两两可达。{5},{6}也分别是两个强连通分量。
Tarjan算法是基于对图深度优先搜索的算法,每个强连通分量为搜索树中的一棵子树。搜索时,把当前搜索树中未处理的节点加入一个堆栈,回溯时可以判断栈顶到栈中的节点是否为一个强连通分量。
定义DFN(u)为节点u搜索的次序编号(时间戳),Low(u)为u或u的子树能够追溯到的最早的栈中节点的次序号。由定义可以得出,
Low(u)=Min{DFN(u),Low(v),(u,v)为树枝边,u为v的父节点{ 如果下一个要访问的V节点,没有访问过,则low[U]=min(low[u],low[v])。 DFN(v),(u,v)为指向栈中节点的后向边(非横叉边)} {如果已经在栈中了,则low[U]=min(low[u],dfn[v]) |
当DFN(u)=Low(u)时,以u为根的搜索子树上所有节点是一个强连通分量。
依照上面红色字体的定义,只要当DFN[U]=LOW[U] 便说明此时栈中的元素,从元素U以上的栈中元素都属于同一个强连通分量。
具体的分步分析过程请参考百度文库(http://wenku.baidu.com/view/ceb92fe2524de518964b7d66.html);
下面给出TARJAN算法的具体代码:
#include <cstdio> #include <cstdlib> struct { int x,y,n; }e[1000]; int f[1000]; int o; bool v[1000]; bool vs[1000]; int b[1000][1000],dfn[1000],low[1000],zhan=0,lian,ti=0; int stick[1000]; int min(int a,int b) { return (a<b)?a:b; } void add(int a,int b) { o++; e[o].x=a; e[o].y=b; e[o].n=f[a]; f[a]=o; } void tanzhan(int u) { lian++; int j=1; while (stick[zhan]!=u) { b[lian][j++]=stick[zhan--]; vs[stick[zhan]]=false; } b[lian][j++]=stick[zhan];{B数组记录的是每一个强连通分量,及每一个强连通分量中的元素} vs[u]=false; b[lian][0]=j-1; } void tarjan(int u) { dfn[u]=++ti; if (low[u]==0) low[u]=dfn[u]; stick[++zhan]=u; vs[u]=true;{VS表示当前元素是否在模拟的栈中} int t=f[u]; v[u]=true; while (e[t].y!=0) { if (v[e[t].y]==false) { tarjan(e[t].y); low[u]=min(low[u],low[e[t].y]);{由上面红色字体的定义,更新每一个点的LOW值和DFN值} }else { if (vs[e[t].y]==true) low[u]=min(low[u],dfn[e[t].y]); } t=e[t].n; }//这里没有回溯的过程,因此TARJAN是O(M+N)的算法。 if (dfn[u]==low[u]) tanzhan(u); } int main() { int m; freopen("tarjan.in","r",stdin); freopen("tarjan.out","w",stdout); scanf("%d",&m); for (int i=1;i<=m;i++) { int a,b; scanf("%d%d",&a,&b); add(a,b); } for (int i=1;i<=6;i++) { if (v[i]==false) tarjan(i); } for (int i=1;i<=6;i++) {printf("%d\n",dfn[i]); printf("%d\n",low[i]);} return 0; }
图中的元素采用模拟链表存储,其中需要注意的是,因为tarjan算法是只会对每一个图中的节点访问一遍,因此不需要回溯(即V数组,只会更新一遍)
本文地址:http://www.cnblogs.com/foreverzsz/archive/2010/11/07/1870926.html
{foreverzsz 原创,转载请注明出处.}