强连通分量
割点
针对无向连通图,若删除一个点后使得该图不连通,则该点是割点。
void tarjan(int x,int fa){//记录一个fa,代表当前点的父亲
dfn[x]=low[x]=++tot;
int child=0;//以x为根的子树的个数
for(int e=head[x];e;e=nxt[e]){
if(!dfn[to[e]]){
tarjan(to[e],x);//扩展
low[x]=min(low[x],low[to[e]]);//回溯low
if(x==fa) child++;//只有在当前点是根时用记录child
if(x!=fa&&low[to[e]]>=dfn[x]) book[x]=1;//如果一个点不是根,并且它的儿子在不经过它的情况下无法回到它的父亲,那么它也是割点
}
else if(to[e]!=fa) low[x]=min(low[x],dfn[to[e]]);//如果一个点被搜索过了并且是x的儿子或者是它的父亲,就可以直接回溯
}
if(x==fa&&child>=2) book[x]=1;//如果一个点是根并且有多于两个子树,就是割点
return ;
}
割边
在一个无向连通图中,如果删去其中一条边后,连通块的数量会增多,那么我们称这条边为桥或者是割边.
void tarjan(int x,int fa){
dfn[x]=low[x]=++tot;
for(int e=head[x];e;e=nxt[e]){
if(!dfn[to[e]]){
tarjan(to[e],x);//扩展
low[x]=min(low[x],low[to[e]]);//回溯low
if(low[to[e]]>dfn[x]) printf("%d->%d\n",x,to[e]);//如果两点之间只有这一条路径,那么它是割边
}
else if(to[e]!=fa) low[x]=min(low[x],dfn[to[e]]);//如果一个点被搜索过了并且是x的儿子或者是它的父亲,就可以直接回溯
}
return ;
}