tarjan算法在各种各样的图论问题中有着广泛的应用。现在,我们讨论tarjan算法在求无向图的割点时的应用。
无向图的割点,指在一张连通的无向图中,若删去一个点及其所有连边,该无向图就不再联通,则这个点被称为这张无向图的割点。为了求割点,我们引入几个概念:
(1)树边:指在dfs时被经过的边
(2)回边:即非树边
(3)dfs数组:即dfs序
(4)low数组:每个点的子树内的点通过回边能到达的dfs序最小的点的dfs序
可以发现,一个点的dfs序一定比能从这个点经回边到达的点的dfs序大。那么,如果我们找到一个点,使得它的子树内的所有点都不能hui通过回边到达dfs序比它小的点,这个点就是我们要找的割点。对于dfs树上的节点,若某个节点有两棵及以上子树,那么这个点也是割点。
在求low时,我们首先默认每个点的low都与dfs序相等(这时没有搜索到任意一条回边),当搜索到回边时,就将其终点的dfs序与当前点的low比较并取最小值(即“通过回边到达的dfs序最小的点”),递归求解(每搜索完以可子树,就尝试用子树内的low更新根节点的low)即可。
注意
(1)给出的图不一定是连通图,我们应该对每个连通块进行求割点操作。
(2)在统计割点个数时,不能在每次找到割点后直接向计数器内+1,我们使用的求割点算法会重复计算某些点。
AC代码:
#include<cstdio>
#include<algorithm>
const int ma=1e5+5;
using namespace std;
int n,m,head[ma],ecnt=1;//邻接表
int x,y,f[ma];
int ctp[ma],cctp,dfn[ma],low[ma],dfsn=0;//ctp:割点 cctp:割点个数
struct list{
<