Tarjan学习笔记
0 前言
tarjan 算法并不仅仅是一种算法,其中神秘的思想与逻辑令人惊叹。
由于笔者太弱,在此只展示 tarjan 算法求割点的方式。
1 正儿八经的算法简介
Tarjan 算法是基于深度优先搜索的算法,用于求解图的连通性问题。
Tarjan 算法可以在线性时间内求出无向图的割点与桥,进一步地可以求解无向图的双连通分量;同时,也可以求解有向图的强连通分量、必经点与必经边。
2 前置知识
1 割点
割点的定义是:对于一张联通图
听不懂是吧,我也不懂,对于初学者,我们只需要知道:删掉割点和与其相连的边之后,图不联通了。
2 时间戳
时间戳是一种对点进行编号的一种方式,具体是在深度优先搜索时,统计每个点第一次进入的时间。
3 搜索树
在图
3 关于追溯值
这是 tarjan 算法中最神奇的东西,也是初学者最难理解的地方,我会尽量以清晰易懂的方式讲解。
在此,先给出 lyd 在《算法竞赛进阶指南》中给出的定义:
设以
-
-
通过一条不在搜索树上的边,能到达
\text{subtree}(x) 的节点。
是不是很晕?我也晕。
我们结合例图来理解一下。
图中用红色标出的边为树边,对于
接下来考虑
然后考虑与
-
若
y 为x 在搜索树上的子节点,\text{low}(x) = \min(\text{low}(y),\text{low}(x)) 。- 解释:因为
y 为x 的子节点,y 可达的x 经过(x,y) 肯定也可达,根据定义,取较小值。
- 解释:因为
-
若
(x,y) 为非树边,根据定义,我们只能取\text{dfn}(y) 来更新\text{low}(x) 。就像例图中(7,10) 这条边,10 可达7 但不一定能到达比7 更早的节点。
4 如何求割点
tarjan 算法告诉我们:如果
由定义,
但是:对于根节点,我们显然发现,这样是行不通的。如下图:
我们如果钦定
-
若
s 有两颗及以上的子树,那么s 即为割点- 显然,割掉
s 后,它的所有子树之间互不联通,所以s 为割点
- 显然,割掉
5 代码实现
void tarjan(int x,bool root){
int ch = 0;
low[x] = dfn[x] = ++tot;//初始化
for(int i = head[x];i;i = e[i].nxt){
int y = e[i].to;
if(!dfn[y]){//在搜索树上
tarjan(y,0);//先递归
low[x] = min(low[x],low[y]);//求low
if(low[y] >= dfn[x] && !root) ans[x] = 1;//判定方式1
if(root) ch ++;//判定方式2
}
else low[x] = min(low[x], dfn[y]);//求low
}
if(root && ch >= 2){//判定方式2
ans[x] = 1;
return ;
}
return ;
}
本文码字时间共计
如果您有任何不懂的地方,欢迎私信询问。谢谢!