2 条题解

  • 0
    @ 2026-8-13 15:47:38

    边双连通分量有两种求法,本文将一一介绍。

    前置知识: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.强连通分量解

    再次思考边双连通分量的定义,我们发现,在一个边双连通分量中,对于任意两个点,总有两条路径连接它们,那么这就意味着它们一定存在于同一个环上。

    而我们又发现,强连通分量内的任意两点都互相可达,那么这两个点也都存在于同一个环上。

    那这就简单了,边双连通分量就可以当作是无向图上的强连通分量,解法上自然也没什么差别了(甚至因为无向图没有前向边与横插边,所以可以把 insins 剩下来)。

    代码:

    #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
      @ 2025-12-8 18:15:34
      #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

      双边连通分量(Two-Edge-Connected Components)

      信息

      ID
      8165
      时间
      200ms
      内存
      1024MiB
      难度
      6
      标签
      递交数
      22
      已通过
      11
      上传者