邊雙連通
阿新 • • 發佈:2020-12-10
/* * 求邊雙連通分量 * 整體思路就是在圖上dfs 並記錄時間戳 * 相較於有向圖 只需要注意一條邊的兩個節點即可 */ #include <bits/stdc++.h> #define N 1000010 #define p(a) putchar(a) using namespace std; int n,m; struct edge{ int to,from,next; }e[N<<1];int head[N],cntedge=1;//前向星存邊,注意邊從二開始 void addedge(int from,int to){ e[++cntedge]={to,from,head[from]}; head[from]=cntedge; swap(from,to); e[++cntedge]={to,from,head[from]}; head[from]=cntedge; }; int f[N];//記錄點是由哪條邊訪問 int dfn[N],low[N],num,cnt,from[N],cut[N];//dfn:tarjan時間戳 low:tarjan的low num:時間戳 計數器, from[i]:i號節點的連通分量 cnt:連通分量的個數 cut[i]:i號邊是否為橋邊 int tarjan(int u,int fa){ dfn[u]=low[u]=++num; for(int i=head[u];i;i=e[i].next){ int v=e[i].to; if(!dfn[v]){ f[v]=i>>1,tarjan(v,u); low[u]=min(low[v],low[u]); }else if(v!=fa){// low[u]=min(low[u],dfn[v]); } } if(f[u]&&low[u]==dfn[u]){ cut[f[u]]=1; } } void dfs(int x,int y){ from[x]=y; for(int i=head[x];i;i=e[i].next){ int v=e[i].to; if(!from[v]&&!cut[i>>1]){ dfs(v,y); } } } signed main(){ in(n);in(m); for(int x,y,i=1;i<=m;i++){ in(x);in(y); addedge(x,y); } tarjan(1,0); for(int i=1;i<=n;i++){ if(!from[i])dfs(i,++cnt); } return 0; }