其实tarjan算法提出的思想就是DFS深度优先遍历,在遍历的过程中记录某些变量的值,来解决相关问题,下面两个经典的问题都能通过tarjan的思想去解决。在此表达对Robert Tarjan的崇高敬意。
连通
基础思想
就是通过DFS,在深度优先遍历的过程中,记录每个节点上对应的值,在编程中我们需要记录的每个节点的值有DFN(访问的次序),inStack(是否在栈中,引入的栈是做什么的,下面会演示),LOW(记录该节点可以追溯到的节点的时间戳),然后通过比较DFN和LOW的值去判断该节点是否能构成连通分量。
伪代码
void varjan(节点 t)//深搜
对于与节点t相连的每个节点i
如果i没有访问过,则
varjan(i)//继续深搜
LOW[t]=min(LOW[i],LOW[t]);//回朔到该点时;
如果i访问过,并且i在栈中,那么
LOW[t]=min(LOW[t],DFN[i]);
if LOW[t]==DFN[t]
输出栈中位于t前面的所有的节点为一个连通风量。
下面我们通过题目去讲解tarjan的思想,看一下是如何判断一个图是否是连通图的。
这是一个老图,了解强连通的应该可以看出来,该图有三个连通分量分别为{1,2,3,4},{5},{6}
那么如何利用程序去寻找该图中有那些连通分量呢?
1.我们以节点1为开始节点,去深度优先别的遍历每一个节点。
2.到节点6的时候,我们发现6没有子节点,于是判断其DFN与LOW是否相等,相等则弹出栈中6以上的所有节点为一个连通分量,可知只有6一个。
3.回溯到5,发现与节点6一样,找不到未访问的子节点。于是栈中弹出5然后继续回溯。
4.然后继续从节点2开始深度优先访问4,则4的DFN和LOW即为5;当访问4->1路线时,发现1节点已经访问过了,而且存在栈中,所以使得LOW[4]=min{DFN1,LOW[4]}=1;
5.节点4的子节点都访问完了,判断DFN[4]不等于LOW[4],所以继续回朔到2,LOW[2]=min{LOW[4],LOW[2]}=1。又因为节点2的所有子节点也访问完了,所以判断DFN[2]不等于LOW[2],继续回朔,访问节点3。过程是一样的,就不分析了。下面结合代码去更好的理解。
代码实现
//============================================================================
// Name : Tarjan.cpp
// Author : SELOUS
// Version :
// Copy