2 条题解
-
0
边双连通分量有两种求法,本文将一一介绍。
前置知识:tarjan 求割边/tarjan 求强连通分量。
1.割边解法:
容易发现,边双连通分量的定义等价于一个不存在割边的连通分量,所以 tarjan 跑一边割边,再对每一个点跑一下 DFS 就能直接算出来每一个边双连通分量。
代码:
#include<bits/stdc++.h> using namespace std; const int mx=5e5+5; struct edge{ int v,id; bool operator <(const edge &ano)const{ if(v==ano.v){ return id<ano.id; } return v<ano.v; } }; vector<edge> g[mx]; vector<int> bcc[mx]; bool cut[mx<<2],vis[mx]; int dfn[mx],low[mx],tim,id; void tarjan(int u,int in){ dfn[u]=low[u]=++tim; for(auto nxt:g[u]){ int v=nxt.v,id=nxt.id; if(!dfn[v]){ tarjan(v,id); low[u]=min(low[u],low[v]); if(low[v]>dfn[u]){ cut[id]=1; } } else if(in!=id){ low[u]=min(low[u],dfn[v]); } } } void dfs(int u){ vis[u]=1; bcc[id].push_back(u); for(auto nxt:g[u]){ int v=nxt.v,id=nxt.id; if(!vis[v] && !cut[id]){ dfs(v); } } } int main(){ ios::sync_with_stdio(0); cin.tie(0); int n,m; cin>>n>>m; for(int i=1;i<=m;i++){ int x,y; cin>>x>>y; x++;y++; g[x].push_back({y,i}); g[y].push_back({x,i}); } for(int i=1;i<=n;i++){ if(!dfn[i]){ tarjan(i,-1); } } for(int i=1;i<=n;i++){ if(!vis[i]){ id++; dfs(i); } } cout<<id<<"\n"; for(int i=1;i<=id;i++){ cout<<bcc[i].size()<<" "; for(auto v:bcc[i]){ cout<<v-1<<" "; } cout<<"\n"; } return 0; }2.强连通分量解
再次思考边双连通分量的定义,我们发现,在一个边双连通分量中,对于任意两个点,总有两条路径连接它们,那么这就意味着它们一定存在于同一个环上。
而我们又发现,强连通分量内的任意两点都互相可达,那么这两个点也都存在于同一个环上。
那这就简单了,边双连通分量就可以当作是无向图上的强连通分量,解法上自然也没什么差别了(甚至因为无向图没有前向边与横插边,所以可以把 剩下来)。
代码:
#include<bits/stdc++.h> using namespace std; struct edge{ int to,id; }; int dfn[500005],low[500005],tim; int bh[500005],id; int in[500005]; stack<int> st; vector<int>dcc[500005]; vector<edge> g[500005]; void tarjan(int u,int from){ st.push(u); dfn[u]=low[u]=++tim; for(auto v:g[u]){ if(v.id==from){ continue; } if(!dfn[v.to]){ tarjan(v.to,v.id); low[u]=min(low[u],low[v.to]); } else{ low[u]=min(low[u],dfn[v.to]); } } if(low[u]==dfn[u]){ int pr; id++; do{ pr=st.top(); st.pop(); bh[pr]=id; dcc[id].push_back(pr); } while(pr!=u); } } int main(){ int n,m; cin>>n>>m; for(int i=1;i<=m;i++){ int x,y; cin>>x>>y; x++,y++; g[x].push_back({y,i}); g[y].push_back({x,i}); } for(int i=1;i<=n;i++){ if(!dfn[i]){ tarjan(i,-1); } } cout<<id<<"\n"; for(int i=1;i<=id;i++){ cout<<dcc[i].size()<<" "; for(auto v:dcc[i]){ cout<<v-1<<" "; } cout<<"\n"; } return 0; } -
0
#include<bits/stdc++.h> using namespace std; const int N=2e5+10; vector<pair<int,int>>G[N]; int dfn[N],low[N],tsp,cnt,siz[N];vector<int>edcc[N]; stack<int>stk;bool instk[N]; void tarjan(int x,int f) { dfn[x]=low[x]=++tsp; stk.push(x);instk[x]=1; for(auto i:G[x])if(i.second!=f) { int y=i.first,id=i.second; if(!dfn[y]) { tarjan(y,id); low[x]=min(low[x],low[y]); } else if(instk[y])low[x]=min(low[x],dfn[y]); } if(dfn[x]==low[x]) { cnt++; int z=-1; for(;z!=x;) { z=stk.top();stk.pop();instk[z]=0; edcc[cnt].push_back(z);siz[cnt]++; } } } int main() { int n,m;cin>>n>>m; for(int i=1;i<=m;i++) { int x,y;cin>>x>>y;x++,y++; G[x].push_back({y,i}); G[y].push_back({x,i}); } for(int i=1;i<=n;i++)if(!dfn[i])tarjan(i,0); cout<<cnt<<'\n'; for(int i=1;i<=cnt;i++) { cout<<siz[i]<<' '; for(int y:edcc[i])cout<<y-1<<' '; cout<<'\n'; } return 0; }
- 1
信息
- ID
- 8165
- 时间
- 200ms
- 内存
- 1024MiB
- 难度
- 6
- 标签
- 递交数
- 22
- 已通过
- 11
- 上传者