Tarjan算法的相关应用
强连通分量
定义略。
用Tarjan算法来求解强连通分量,在此之前,先明确这两个定义:
-
返祖边:由一个点指向其祖先的边。
-
横插边: 由一个节点指向非祖先节点的边。(只有有向图会出现)
这两种边都是dfs树的非树边。
定义这两个数组:
-
: dfs序。
-
: 不经横插边所能到达的点中最小的。
1 | if(!dfn[v]){ |
不难发现,对于某个节点,表示其深度最小的祖先的。这样一来,当某个点的等于时,就说明找到了新的强连通分量。用一个栈来维护强连通分量里的节点,具体操作如下:
-
更新和的初值。
-
当前节点进栈。
-
遍历当前节点的子节点:
-
如果未被访问,说明在dfs树上在的子树中,对继续dfs。用更新。
-
如果被访问且在栈中,说明是一条返祖边。用更新。
-
-
执行完上述操作后,如果的和相等,说明找到了一个新的强连通分量,则:
-
将栈中及其之后的所有节点出栈。
-
标记强连通分量。
-
代码:
1 | void tarjan(int u){ |
缩点
由于强连通分量内的点可以互相到达,可以将强连通分量缩成一个点,这样可以得到一个有向无环图。
缩点的流程如下:
-
遍历所有节点:
-
遍历的所有子节点:
- 如果和不属于同一个强连通分量,就从所在的强连通分量向所在的强连通分量连边。
-
代码:
1 | void suodian(){ |
割点
在无向图中,对于一个点,如果删除这个点及其连边后,连通块数量增加,那么这就是一个割点。
判断一个点是割点的充分条件如下:
-
若为根,有两个及以上子节点。
-
若不为根,在dfs树中的子树中。
代码:
1 | void tarjan(int u,int fa){ //由于是无向图,需要记录父亲节点 |
割边
定义类似割点
一条边,当且仅当low_v\geq \dfn_u。
点双连通分量
不存在割点的连通子图。
Tarjan算法的相关应用