LGP8436 [LG TPLT] 边双连通分量 学习笔记
LGP8436 [LG TPLT] 边双连通分量 学习笔记
题意简述
给定一个 \(n\) 点 \(m\) 边的无向图。求其所有边双连通分量。
做法解析
我们仍用 \(\texttt{tarjan}\) 算法求解。其实,求解边双和求解强连通分量几乎是一致的:无向图 \(\texttt{DFS}\) 生成树上的一个强连通分量就对应原图上的一个双连通分量。
你可以理解为:无向图 \(\texttt{DFS}\) 生成树上有强连通分量,意味着它可以按某个方向“顺着”遍历整个分量里的点,而原图的边都是无向,也即双向的,意味着它也一定能“逆着”遍历完整个分量。
代码实现
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=5e5+5;
int N,M,X,Y,ecnt;
vector<pii> Gr[MaxN];
void addudge(int u,int v){
Gr[u].push_back({v,++ecnt});
Gr[v].push_back({u,ecnt});
}
int tot,dfn[MaxN],low[MaxN],stk[MaxN],ktp,bcnt;
int bel[MaxN];vector<int> bcc[MaxN];
void tarjan(int u,int fe){
dfn[u]=low[u]=++tot,stk[++ktp]=u;
for(auto [v,ce] : Gr[u]){
if(ce==fe)continue;
if(!dfn[v])tarjan(v,ce),minner(low[u],low[v]);
else if(!bel[v])minner(low[u],dfn[v]);
}
if(low[u]==dfn[u]){
bcnt++;int v;
do{v=stk[ktp--];bcc[bcnt].push_back(v),bel[v]=bcnt;}while(v!=u);
}
}
int main(){
readis(N,M);
for(int i=1;i<=M;i++)readis(X,Y),addudge(X,Y);
for(int i=1;i<=N;i++)if(!dfn[i])ktp=0,tarjan(i,0);
writil(bcnt);
for(int i=1;i<=bcnt;i++){
writip(bcc[i].size());
for(int j : bcc[i])writip(j);
puts("");
}
return 0;
}
浙公网安备 33010602011771号