Tarjan貌似跟Hopcroft都是Cornell的大神。总的来说, Tarjan算法基于一个观察,即:同处于一个SCC中的结点必然构成DFS树的一棵子树。 我们要找SCC,就得找到它在DFS树上的根。
那么怎么找呢?
考虑一下,如果DFS访问到了某个结点u,又顺着u来到了结点v, 但从v发出了一条反向边,指向了u的前驱w,那根据DFS的性质, u->v->w->u构成了一个环。这一堆东西必然处于同一个SCC。 所以某个要找到SCC子树的根,就得找那个在DFS树中最早被发现的结点,且这个结点要与它的一堆后继结点形成环。
这时候DFS的特性就派上用场了。最早发现的结点可以通过记录发现时间来实现,而反向边的判断可以通过结点颜色,即访问状态来实现。 定义一个结点的low值为:从该节点的子树结点可达的,尚未求出属于哪个SCC的结点的最早访问时间。 由于SCC构成子树,所以求没求出某个结点所在的SCC用栈来刻画就可以了: 每次访问到一个结点u,记录发现时间visit,并将它推到栈里去。 如果从u可达的结点v没访问过,那么访问v,用v的low值更新u; 否则,如果v已访问过,那就看看它在不在栈中。如果在,说明还没确定v到底属于哪个SCC, 这时(u, v)就是一条反向边了,根据v的visit值,更新u的low值即可。 最后回到u结点时,如果u的low值和visit相等了,显然u就是我们要找的根节点了。 从栈里把u和其上所有结点弹出来,这一堆东西就在一个SCC里了。
https://blog.csdn.net/sdsy191553/article/details/79674201
看的我迷迷糊糊的