tarjan强连通分量算法个人理解

来源:互联网 发布:淘宝的等级怎么升级快 编辑:程序博客网 时间:2024/05/17 04:10

图中的强连通分量是指图中的一块区域,其中任意两点都能找到到对方的路,而且这块区域不能再加入别的点。

一个环就是一个的强连通分量。
长得复杂一点的强连通分量不过是有公共节点的多个环而已。 //有公共边肯定有公共节点
所以求强连通分量实际上是个找环问题。
找单个环的话,用dfs转一圈回到自己就能找到一个环,但是我们要找的是套在一起的所有环,那就把dfs改一下。
既然dfs转回自己是成环的条件,那么我们称该点为环的根节点,这一点满足在dfs遍历过程中它能转回的最早出现的点是自己(不然更早出现的点能转回这个所谓的“根节点”,就有更大的环了)。
我们按照dfs遍历的顺序把节点压入栈,然后在根节点完成dfs时出栈,直到根节点出栈,即得到强连通分量。

如图我们转圈圈的顺序是
1->3->5->6
6出栈
5出栈
4->1 发现4能转回1,更新4,3,1能转回的最早时间
1->2->4 发现2能转回4,更新2能转回的最早时间
1的dfs完成,发现自己能转回的最早点是自己
2出栈
4出栈
3出栈
1出栈
完成!!

int dfn[1000]={0};      //节点在dfs过程中出现的时间int low[1000];          //一个节点能转回的最早出现的节点出现的时间int stk[1000];          //节点栈int vis[1000];          //节点是否在栈中int stktop=0;           //栈顶位置int ind=0;              //当前时间int n,m;                //点数,边数void tarjan(int pos){    dfn[pos]=low[pos]=++ind;//更新时间    stk[stktop++]=pos;//入栈    vis[pos]=1;//我在栈里!!    for(int i=0;i<n;i++)        if(graph[pos][i]!=inf)            if(dfn[i]==0)//如果这个点没来过            {                tarjan(i);//和dfs一样,就接着往深处去                low[pos]=low[pos]<low[i]?low[pos]:low[i];//如果我的后代能转回我的祖先,我肯定能!            }            else if(vis[i])                low[pos]=low[pos]<dfn[i]?low[pos]:dfn[i];//让我能转回的节点保持最早    if(dfn[pos]==low[pos])//能转回的最早出现的点是自己,已确认是根节点,开始出栈    {        vis[pos]=0;        while(stk[--stktop]!=pos)        {            //强连通分量求出来了,干点什么吧            //dosth(stk[stktop]);        }    }}
原创粉丝点击