Tarjan学习

学习博客:https://www.cnblogs.com/stxy-ferryman/p/7779347.html

1.求(点个数大于1的)强连通分量个数

题目链接:https://www.luogu.com.cn/problem/P2863

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+5;
vector<int> G[N];
int dfn[N];//表示这个点在dfs时是第几个被搜到的 
int low[N];//表示这个点以及其子孙节点连的所有点中dfn最小的值
int st[N],top=0;//表示当前所有可能能构成是强连通分量的点。
bool vis[N];//表示一个点是否在stack[ ]数组中
int cnt=0;//时间戳 
int color[N];//每个点属于第几个强连通分量 
int cn=0;//colornum强连通分量的个数 
void tarjan(int u){
	dfn[u]=low[u]=++cnt;
	vis[u]=true;
	st[++top]=u;
	for(int i=0;i<G[u].size();i++){
		int &v=G[u][i];
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v]){
			low[u]=min(low[u],low[v]);
		}
	}
	if(dfn[u]==low[u]){
		color[u]=++cn;
		vis[u]=0;
		int v;
		do{
			v=st[top--];
			color[v]=cn;
			vis[v]=false; 
		}while(u!=v);
	}
}
int num[N];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
    	int u,v;
    	scanf("%d%d",&u,&v);
    	G[u].push_back(v);
	}
    for(int i=1;i<=n;i++){
    	if(!dfn[i]) tarjan(i);
	}
	for(int i=1;i<=n;i++) num[color[i]]++;
	int ans=0;
	for(int i=1;i<=cn;i++){
		if(num[i]>1) ans++;
	}
	printf("%d\n",ans);
	return 0;
}

2.tarjan缩点

题目链接:https://vjudge.net/problem/POJ-2186

#include<cstdio>
#include<algorithm>
#include<vector> 
using namespace std;
typedef long long ll;
const int N=5e4+5;
vector<int> G[N];
int dfn[N];//表示这个点在dfs时是第几个被搜到的 
int low[N];//表示这个点以及其子孙节点连的所有点中dfn最小的值
int st[N],top=0;//表示当前所有可能能构成是强连通分量的点。
bool vis[N];//表示一个点是否在stack[ ]数组中
int cnt=0;//时间戳 
int color[N];//每个点属于第几个强连通分量 
int cn=0;//colornum强连通分量的个数 
void tarjan(int u){
	dfn[u]=low[u]=++cnt;
	vis[u]=true;
	st[++top]=u;
	for(int i=0;i<G[u].size();i++){
		int &v=G[u][i];
		if(!dfn[v]){
			tarjan(v);
			low[u]=min(low[u],low[v]);
		}
		else if(vis[v]){
			low[u]=min(low[u],low[v]);
		}
	}
	if(dfn[u]==low[u]){
		color[u]=++cn;
		vis[u]=0;
		int v;
		do{
			v=st[top--];
			color[v]=cn;
			vis[v]=false; 
		}while(u!=v);
	}
}
int deg[N],num[N];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
    	int u,v;
    	scanf("%d%d",&u,&v);
    	G[u].push_back(v);
	}
    for(int i=1;i<=n;i++){
    	if(!dfn[i]) tarjan(i);
	}
	for(int i=1;i<=n;i++){
		num[color[i]]++;
		for(int j=0;j<G[i].size();j++){
			int &v=G[i][j];
			if(color[i]!=color[v]) deg[color[i]]++;
		}
	}
	int ans=0,tmp=0;
	for(int i=1;i<=cn;i++){
		if(deg[i]==0){
			tmp++;
			ans=num[i];
		}
	}
	if(tmp==1) printf("%d\n",ans);
	else printf("0\n");
	return 0;
}

3.求无向图割点

题目链接:https://www.luogu.com.cn/problem/P3388

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+5;
vector<int> G[N];
int dfn[N];//表示这个点在dfs时是第几个被搜到的 
int low[N];//表示这个点以及其子孙节点连的所有点中dfn最小的值
int cnt=0;//时间戳 
bool cut[N];
void tarjan(int u,int fa){
	int child=0;
	dfn[u]=low[u]=++cnt;
	for(int i=0;i<G[u].size();i++){
		int &v=G[u][i];
		if(!dfn[v]){
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u]&&u!=fa) cut[u]=true;
			if(u==fa) child++;
		}
		low[u]=min(low[u],dfn[v]);		
	}
	if(child>=2&&u==fa) cut[u]=true;
}
int num[N];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++){
    	int u,v;
    	scanf("%d%d",&u,&v);
    	G[u].push_back(v);
    	G[v].push_back(u);
	}
    for(int i=1;i<=n;i++){
    	if(!dfn[i]) tarjan(i,i);
	}
	int ans=0;
	for(int i=1;i<=n;i++) if(cut[i]) ans++;
	printf("%d\n",ans);	
	for(int i=1;i<=n;i++){
		if(cut[i]) printf("%d ",i);
	}
	return 0;
}


4.求无向图桥

题目链接:https://vjudge.net/problem/UVA-796

#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const int N=1e4+5;
vector<int> G[N];
int dfn[N];//表示这个点在dfs时是第几个被搜到的 
int low[N];//表示这个点以及其子孙节点连的所有点中dfn最小的值
int cnt=0;//时间戳 
struct node{
	int x,y;
	bool operator<(const node &other)const{
		if(x!=other.x) return x<other.x;
		else return y<other.y;
	}
};
vector<node> ans; 
unordered_map<int,int>mp;
void add_bridge(int x,int y){
	if(x>y) swap(x,y);
	ans.push_back(node{x,y});
}
void tarjan(int u,int fa){
	dfn[u]=low[u]=++cnt;
	for(int i=0;i<G[u].size();i++){
		int &v=G[u][i];
		if(!dfn[v]){
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
			if(low[v]>dfn[u]) add_bridge(u,v);
		}
		else if(dfn[v]<dfn[u]&&v!=fa) low[u]=min(low[u],dfn[v]);
	}
}
bool Hash(int u,int v){//hash去重 
	if(mp[u*N+v]) return true;
	if(mp[v*N+u]) return true;
	mp[u*N+v]=mp[v*N+u]=true;
	return false;
}
void init(int n){
	mp.clear();
	ans.clear();
	cnt=0;
	for(int i=0;i<=n;i++){
		dfn[i]=low[i]=0;
		G[i].clear();
	} 
}
int main(){
    int n;
    while(~scanf("%d",&n)){
    	init(n);
    	for(int i=1;i<=n;i++){
    		int u,v,k;
    		scanf("%d (%d)",&u,&k);
    		while(k--){
    			scanf("%d",&v);
    			if(Hash(u,v)) continue;
    			G[u].push_back(v);
    			G[v].push_back(u);
			}
		}
		for(int i=0;i<n;i++){
			if(!dfn[i]) tarjan(i,i);
		}
		sort(ans.begin(),ans.end());
		printf("%d critical links\n",ans.size());
		for(int i=0;i<ans.size();i++) {
			printf("%d - %d\n",ans[i].x,ans[i].y);
		}
		printf("\n");
	}
	return 0;
}
发布了415 篇原创文章 · 获赞 47 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/qq_42936517/article/details/103462352