寻找图的强连通份量:tarjan算法简单理解

一、简介
tarjan是一种使用深度优先遍历(DFS)来寻找有向图强连通份量的一种算法。算法

二、知识准备
栈、有向图、强连通份量、DFS。数组

三、快速理解tarjan算法的运行机制
提到DFS,能想到的是经过栈来储存沿途的点,能够找到全部的环。环自己就是联通的,因此环对于强连通份量来讲环已经很接近最终答案了。要把找环变成找强连通管份量还要考虑:
a.在环外是否是有其余环在这个强连通份量内(极大性)spa

(会被认为是2个环).net

b.一些不能构成环的点没法被考虑到,而他们自己就是强连通份量code

(2不被认为是一个强连通份量)blog

 

因此Tarjan算法除了栈还引入了2个数组,分别是:
DFN[N]//节点的时间戳,用来标记节点访问的前后顺序(以及是否被访问过)
Low[N]//当前“环”里最早被访问到的节点,至关于当前这个强连通份量里的根class


Tarjan的流程是:
DFS,每遇到一个未被访问过的节点就初始化DFN[i]=Low[i]=index++;
若是找到了环,就在遍历中用Low数组向上传递根的时间戳,直到找到一个点他的时间戳和根的时间戳一致,即DFN[i]=Low[i],这就说明这个点就是根。此时,栈内的全部在根后面的点(包括根)就组成一个强连通份量。遍历

四、伪代码im

index=0;
tarjan(u)
{
    DFN[u]=low[u]=index++;
    u入栈;
    for(遍历每条边(u,v))
    {
        if(v未被访问)
        {
            tarjan(v);//DFS
            low[u]=min(low(u),DFN(v));//将下方的时间戳向上传递
        }
        else if(v在栈内)
        {
            low[u]=min(low[u],DFN(v));//找到环,比较当前保存的根的时间戳和v的时间戳,取较早的那个做为根
        }
        if(DFN(u)==low[u])
        {
            //回到了根节点,此时栈内从u日后的节点都是该强连通份量的节点
            //找到了强连通份量,逐个退栈,输出
        }
    }
}


五、进一步说明
a.对于问题a,为何能找到强连通份量内其余的环?
DFS的问题在于,找到了环当即处理而不考虑其余环;Tarjan算法把输出交给根节点处理,在到根节点以前,算法已经遍历的根节点下的全部节点,天然也把全部环放入了栈。
b.对于问题b,为何考虑到了不能构成环的那些节点?
对于这些节点,DFN(u)==low[u],至关于他们自己就是强连通份量的根节点。时间戳

六、延伸阅读若是您仍然有疑问,能够参考https://blog.csdn.net/qq_34374664/article/details/77488976

相关文章
相关标签/搜索