#C240219D. 边双连通分量


#C240219D. 边双连通分量

标签(Label)

  • tarjan
  • 模板

网址(Website)

$\qquad$ P8436 【模板】边双连通分量

题解(Solution)

定义:

$\qquad$边双连通:一张没有割边无向图

$\qquad$边双连通分量:一张无向图中,满足边双连通的子图,且使这个图尽量大,称其为边双连通分量

求法1( tarjan+dfs 法):

$\qquad$先通过 $tarjan$ 跑出割边,然后直接 $dfs$ 求出去除割边后的连通块。

求法2( tarjan跑“强连通分量” 法)

$\qquad$找出无向图的强连通分量,注意不能让当前点从同一条无向边来回。由于存在重边,因此不能通过记录当前的 $father$ 来判断是否走的同一条无向边,可以通过记录上一次走过的边的编号来判断。(直接用 $vector$ 存储 $pair<int,int> $ ,$first$ 用来存当指向的点,$second$ 用来存边的编号)

代码(Code)

#include<bits/stdc++.h>
#include<vector>
#include<stack>
#include<set>
#define For(i,l,r) for(int i=l;i<=r;i++) 
#define Rof(i,l,r) for(int i=l;i>=r;i--)
using namespace std;
#define P pair<int,int>
#define int long long
inline int input(){int x;return cin>>x,x;}
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 501234;

vector<P> ft[N];
stack<int> st;

int n,m,ans;

int dfn[N],low[N],t;
int scc[N],cnt;
vector<int> dc[N];
void tarjan(int x,int last){//last上一条边的编号 
	dfn[x]=low[x]=++t,st.emplace(x);
	for(auto p:ft[x]){
		int y=p.first,id=p.second;
		//!!!特别注意:只是不能走上一条边,并不是不能走上一个点!!! 
		if(!dfn[y]) tarjan(y,id) , low[x] = min(low[x],low[y]);
		else if(!scc[y] && id!=last) low[x] = min(low[x],dfn[y]);
	}if(low[x] == dfn[x]){
		scc[x]=++cnt;
		dc[cnt].emplace_back(x);
		while(st.top() != x){
			scc[st.top()] = cnt;
			dc[cnt].emplace_back(st.top());
			st.pop();
		}st.pop();
	}
} 

signed main(){
	ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
	cin>>n>>m;int Tim = clock();
	For(i,1,m){
		int x=input(),y=input();
		ft[x].emplace_back(y,i);
		ft[y].emplace_back(x,i);
	}//记录边的编号  
	
	For(i,1,n) if(!dfn[i]) tarjan(i,0);
	
	cout<<cnt<<'\n';
	For(i,1,cnt){
		cout<<dc[i].size()<<' ';
		for(auto x:dc[i]) cout<<x<<' ';
		cout<<'\n';
	}
	return cerr<<"TIME:"<<(clock()-Tim)/1024.,0;
}

文章作者: WolfDeer
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WolfDeer !
  目录