对tarjan缩点/求割点/求桥的理解

不适合初学者,适合复习

缩点

d f n [ i ] dfn[i] dfn[i]就是一个 d f s dfs dfs序。
l o w [ i ] low[i] low[i] i i i不通过 i i i的父亲节点能到达的最高(深度最小/ d f s dfs dfs序最小)的祖先节点。
上面两个数组初始化都是 d f s dfs dfs序编号;解释: d f n [ i ] dfn[i] dfn[i]显然,一开始每个点的 l o w [ i ] low[i] low[i]就是自己,也是 d f s dfs dfs序。
然后遍历与之相邻的点:

  • 如果这个点之前没被访问过,就先继续往下递归,回溯回来时用下面点的 l o w [ ] low[] low[]更新当前这个点的 l o w [ ] low[] low[],取下面点 l o w [ ] low[] low[]的最小值,因为这个点可以走到这些点,按照 l o w [ ] low[] low[]的定义需要取 m i n min min
  • 如果这个点被访问过,那就直接用栈里(已经求出的强连通分量)的点的 l o w [ ] low[] low[]更新当前点的 l o w [ ] low[] low[],因为这个点可以到达这些点(因为栈里的点已经是求出的一个强连通分量)。

遍历完这些点之后如果当前节点的 l o w [ ] = d f n [ ] low[]=dfn[] low[]=dfn[],那就说明这个节点的子节点已经没有返祖边了,当前点和当前点的子节点都没有边指向更早的祖先,所以说这个点当前的强连通分量是最大的(为什么求出的强连通分量是最大的)。
记录从栈里弹出来的点就是一个强连通分量(环),然后就可以缩点了。
注意图不一定联通,所以要对每个没搜过的点都跑一遍,判断 d f n [ ] dfn[] dfn[]是否有值即可。

割点与桥的判断

割点和桥是对于无向图而言的。
有割点不一定有桥但有桥一定有割点,可以自己画图尝试一下。
对于割点,如果当前节点 f r fr fr的子树里有一个节点 v v v必须通过当前节点 f r fr fr才能访问到 f r fr fr的祖先借节点,那么 f r fr fr就是一个割点,因为去掉 f r fr fr之后 v v v就与 f r fr fr上面的点不连通了。
也就是在回溯回来时判断 d f n [ f r ] < = l o w [ v ] dfn[fr]<=low[v] dfn[fr]<=low[v],根节点要单独考虑,看是否有一棵以上子树即可。
桥与割点只是点与边的区别,桥就是判断 d f n [ f r ] < l o w [ v ] dfn[fr]dfn[fr]<low[v],去掉了相等的情况。

你可能感兴趣的:(Tarjan,割点)