【图论】tarjan求割点和桥(无向双联通)

参考:https://blog.csdn.net/wtyvhreal/article/details/43530613
因为我是用邻接表写的,所以时间复杂度:O(n+m);
求割点模板:
(前向星):

#include
#define ll long long
#define endl '\n'
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=2e5+10;
ll root;
ll dfn[maxn],low[maxn],tott,n,m,ans=-1,vis[maxn],flag[maxn];
stack<ll> s;
ll tot;ll head[maxn];ll fa[maxn];
struct E{
	ll to,next;
}edge[maxn<<1];
void add(ll u,ll v){
	edge[tot].to=v;
	edge[tot].next=head[u];
	head[u]=tot++;
}
void tarjan(ll x){
	ll child=0;
	low[x]=dfn[x]=++tott;
	for(ll i=head[x];i!=-1;i=edge[i].next){
		ll v=edge[i].to;
		if(!dfn[v]){
			child++;fa[v]=x;
			tarjan(v);
			low[x]=min(low[x],low[v]);
			if(fa[x]!=-1&&low[v]>=dfn[x]) flag[x]=1;
			if(fa[x]==-1&&child>=2) flag[x]=1;
		}else if(v!=fa[x]){
			low[x]=min(low[x],dfn[v]);
		}
	}
}
int main(){
	cin>>n>>m;
	memset(head,-1,sizeof(head));
	memset(fa,-1,sizeof(fa));
	for(ll i=1;i<=m;i++){
		ll u,v;cin>>u>>v;
		add(u,v);add(v,u);
	}
	for(ll i=1;i<=n;i++){
		if(!dfn[i]) tarjan(i);
	}
	cout<<endl;
	for(ll i=1;i<=n;i++){
		if(flag[i]) cout<<i<<" ";
	}
}
/*
7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7

*/

非前向星:

#include
#define ll long long
#define endl '\n'
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=2e5+10;
vector<ll> edge[maxn];
ll root;
ll dfn[maxn],low[maxn],tot,n,m,ans=-1,vis[maxn],flag[maxn];
stack<ll> s;
void tarjan(ll x,ll father){
	ll child=0;
	low[x]=dfn[x]=++tot;
	s.push(x);vis[x]=1;
	for(ll i=0;i<edge[x].size();i++){
		ll v=edge[x][i];
		if(!dfn[v]){
			child++;
			tarjan(v,x);
			low[x]=min(low[x],low[v]);
			if(x!=root&&low[v]>=dfn[x]) flag[x]=1;
			if(x==root&&child==2) flag[x]=1;
		}else if(v!=father){
			low[x]=min(low[x],dfn[v]);
		}
	}
}
int main(){
	cin>>n>>m;
	for(ll i=1;i<=m;i++){
		ll u,v;cin>>u>>v;
		edge[u].push_back(v);
		edge[v].push_back(u);
	}
	root=1;
	for(ll i=1;i<=n;i++){
		if(!dfn[i]) tarjan(i,root);
	}
	cout<<endl;
	for(ll i=1;i<=n;i++){
		if(flag[i]==1) cout<<i<<" ";
	}
}
/*
7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7

*/

求桥模板:
前向星:

#include
#define ll long long
#define endl '\n'
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=2e5+10;
ll root;
ll dfn[maxn],low[maxn],tott,n,m,ans=-1,vis[maxn],flag[maxn];
stack<ll> s;
ll tot;ll head[maxn];ll fa[maxn];
struct E{
	ll to,next;
}edge[maxn<<1];
void add(ll u,ll v){
	edge[tot].to=v;
	edge[tot].next=head[u];
	head[u]=tot++;
}
void tarjan(ll x){
	ll child=0;
	low[x]=dfn[x]=++tott;
	for(ll i=head[x];i!=-1;i=edge[i].next){
		ll v=edge[i].to;
		if(!dfn[v]){
			child++;fa[v]=x;
			tarjan(v);
			low[x]=min(low[x],low[v]);			
			if(low[v]>dfn[x]) {cout<<x<<"->"<<v<<endl;}
		}else if(v!=fa[x]){
			low[x]=min(low[x],dfn[v]);
		}
	}
}
int main(){
	cin>>n>>m;
	memset(head,-1,sizeof(head));
	memset(fa,-1,sizeof(fa));
	for(ll i=1;i<=m;i++){
		ll u,v;cin>>u>>v;
		add(u,v);add(v,u);
	}
	for(ll i=1;i<=n;i++){
		if(!dfn[i]) tarjan(i);
	}
}
/*
7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7

*/


非前向星

#include
#define ll long long
#define endl '\n'
#define IO ios::sync_with_stdio(false);cin.tie(0);
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=2e5+10;
vector<ll> edge[maxn];
ll root;
ll dfn[maxn],low[maxn],tot,n,m,ans=-1,vis[maxn],flag[maxn];
stack<ll> s;
void tarjan(ll x,ll father){
	low[x]=dfn[x]=++tot;
	s.push(x);vis[x]=1;
	for(ll i=0;i<edge[x].size();i++){
		ll v=edge[x][i];
		if(!dfn[v]){
			tarjan(v,x);
			low[x]=min(low[x],low[v]);
			if(low[v]>dfn[x]) printf("%d-%d\n",x,v);
		}else if(v!=father){
			low[x]=min(low[x],dfn[v]);
		}
	}
}
int main(){
	cin>>n>>m;
	for(ll i=1;i<=m;i++){
		ll u,v;cin>>u>>v;
		edge[u].push_back(v);
		edge[v].push_back(u);
	}
	root=1;
	for(ll i=1;i<=n;i++){
		if(!dfn[i]) tarjan(i,root);
	}
}
/*
7 7
1 2
2 3
3 4
2 5
4 5
5 6
5 7

*/

【图论】tarjan求割点和桥(无向双联通)_第1张图片
【图论】tarjan求割点和桥(无向双联通)_第2张图片
【图论】tarjan求割点和桥(无向双联通)_第3张图片

你可能感兴趣的:(图论)