注意:本文只针对无向图。
对于无向图,显然不能只考虑简单的连通关系,应该研究一些更强的连通关系:双连通。
前置芝士
- 点双连通分量:若一个连通分量任意两点间 都存在 至少两条不经过(除起点和终点外)相同点的路径,我们就称这个连通分量 为点双连通分量。
- 边双连通分量:同理,若一个连通分量任意两点间 都存在 至少两条不经过 相同边的路径,我们就称这个连通分量 为边双连通分量。
- Tarjan 求割点和桥
首先要明确的是,若一点(或边)对于原图是割点(或桥),对于其任意包含该点(或边)的子图,该点(或边)仍是割点(或桥)。
可以想到,在一张无向图的点双连通分量中,一个割点所连的点有且只有 \(1\) 个(注意这个点必须是指定点双连通分量中的)。注意不是度数为 \(1\),因为可能有重边。原因是若某割点连接了一点双连通分量中的两个点,必然有删去它后该点双连通分量不连通。反之它就不是割点。
同样的,在一张无向图的边双连通分量中,必然不包含桥。
Tarjan 求点双连通分量
算法流程
首先维护一个栈 \(\mathit{stk}\),一访问点 \(u\),就将 \(u\) 压入 \(\mathit{stk}\)。
书接上回,当判断一点是割点后,我们可以从 \(\mathit{stk}\) 中退点,将这些点加入新的点双中,一直退到 \(v\),注意不要退出 \(u\),但要在当前点双中加入 \(u\)。
因为上文说了,虽在一个点双中,割点连接的点只有 \(1\) 个,即 \(v\),但 \(u\) 还可能在其他点双中,故不能退栈(或者你退完压回去也可以)。
所以注意,不同于强连通分量和接下来要说的边双,一个点可能在多个点双中。
进一步的,我们甚至可以求出删去 \(u\) 后连通分量的增加个数,记为 \(cut_u\)。每当满足 \(\mathit{low}_v\ge \mathit{dfn}_u\),\(cut_u\gets cut_u+1\)。因为一旦删去 \(u\),\(v\) 将与 \(u\) 的祖先脱离联系,导致连通分量数量增加 \(1\)。
其他与求割点相同。
代码
暂无。
Tarjan 求边双连通分量
算法流程
还是同样的维护 \(\mathit{stk}\),当判定边 \((u,v)\) 为桥后,可将 \(stk\) 退到 \(v\),并将退的点加入一个新的边双中。有没有发现边双比点双简单多了?是的,由于桥不能存在于边双中,故退到 \(v\) 即可,没有太多可叽叽歪歪的。
其他与求桥相同。
代码
暂无。
完结撒花!
Tarjan 连通系列正式完结啦!(除了代码)。
以后可能还会更 LCA、LCT、splay 的文章(挖大坑)。
标签:连通,双中,mathit,Tarjan,割点,分量 From: https://www.cnblogs.com/chargedcreeper/p/18124673/tarjan-bcc