(4).对于一个连通图,我们很容易想到,在该连通图中有且仅有一个节点u的DFN值和low值相等。该节点一定是在深度遍历的过程中,该连通图中第一个被访问过的节点,因为它的DFN值和low值最小,不会被该连通图中的其他节点所影响。
下面我们证明为什么仅有一个节点的DFN和low值相等。假设有两个节点的DFN值和low值相等,由于这两个节点的DFN值一定不相同 (DFN值的定义就是深度遍历时被访问的先后次序),所以两个的low值也绝对不相等。由于位于同一个连通图中,所以两个节点必定相互可达,那么两者的low值一定会被另外一个所影响(要看谁的low值更小),所以不可能存在两对DFN值和low值相等的节点。
所以我们在回溯的过程中就能够通过判断节点的low值和DFN值是否相等来判断是否已经找到一个子连通图。由于该连通图中的DFN值和low值相等的节点是该连通图中第一个被访问到的节点,又根据栈的特性(先压入 栈的节点在栈的更里面),则该节点在最里面。所以能够通过不停的弹栈,直到弹出该DFN值和low值相同的节点来弹出该连通图中所有的节点。
Tarjan算法的C++实现代码如下,可以配合上面的图加以理解:
#include
using namespace std;
int DFN[105]; //记录在做dfs时节点的搜索次序
int low[105]; //记录节点能够找到的最先访问的祖先的记号
int count=1; //标记访问次序,时间戳
int stack[105]; //压入栈中
int top=-1;
int flag[105]; //标记节点是否已经在栈中
int number=0;
int j;
int matrix[105][105]={{0,1,1,0,0,0},{0,0,0,1,0,0},{0,0,0,1,1,0},{1,0,0,0,0,1},{0,0,0,0,0,1},{0,0,0,0,0,0}};
int length; //图的长度
void tarjan(int u){
DFN[u]=low[u]=count++; //初始化两个值,自己为能找到的最先访问的祖先
stack[++top]=u;
flag[u]=1; //标记为已经在栈中
for(int v=0;v