tarjan 全家桶

无向图的tarjan

求边双连通分量的个数以及每个边双连通分量的大小以及每个边双连通分量包含哪些点。bridge数组表示一条边是不是桥。

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,M=2e6+10;
struct edge{
	int x,y,pre;
}a[M*2];
int alen,last[N];
void ins(int x,int y)
{
	a[++alen]={x,y,last[x]};
	last[x]=alen;
}
int dfn[N],low[N],id;
bool bridge[M*2];
void tarjan(int x,int in_edge)
{
	low[x]=dfn[x]=++id;
	for(int k=last[x];k;k=a[k].pre)
	{
		int y=a[k].y;
		if(!dfn[y])
		{
			tarjan(y,k);
			low[x]=min(low[x],low[y]);
			if(low[y]>dfn[x]) bridge[k]=bridge[k^1]=1;
		}
		else if(k!=(in_edge^1)) low[x]=min(low[x],dfn[y]);
	}
}
int cnt;
bool v[N];
vector<int> dcc[N];
void dfs(int x)
{
	v[x]=1;
	dcc[cnt].push_back(x);
	for(int k=last[x];k;k=a[k].pre)
	{
		int y=a[k].y;
		if(v[y]||bridge[k]) continue;
		dfs(y);
	}
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	alen=1;memset(last,0,sizeof(last));
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		if(x==y) continue;
		ins(x,y),ins(y,x);
	}
	id=0;
	for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,-1);
	for(int i=1;i<=n;i++) if(!v[i]) cnt++,dfs(i);
	printf("%d\n",cnt);//边双连通分量的数目
	for(int i=1;i<=cnt;i++)
	{
		printf("%d ",(int)dcc[i].size());//当前边双连通分量的大小
		for(auto x:dcc[i]) printf("%d ",x);//当前边双连通分量包含哪些点
	}
	return 0;
}

点双tarjan一定要判断自环!

求一个点是不是割点。cut数组表示一个点是不是割点。

#include<bits/stdc++.h>
using namespace std;
const int N=2e4+10,M=1e5+10;
struct edge{
	int x,y,pre;
}a[M*2];
int alen,last[N];
void ins(int x,int y)
{
	a[++alen]={x,y,last[x]};
	last[x]=alen;
}
int dfn[N],low[N],id,root;
bool cut[N];
void tarjan(int x)
{
	low[x]=dfn[x]=++id;
	int flag=0;
	for(int k=last[x];k;k=a[k].pre)
	{
		int y=a[k].y;
		if(!dfn[y])
		{
			tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x])
			{
				flag++;
				if(x!=root||flag>1) cut[x]=true;
			}
		}
		else low[x]=min(low[x],dfn[y]);
	}
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		ins(x,y),ins(y,x);
	}
	for(int i=1;i<=n;i++) if(!dfn[i]) root=i,tarjan(i);
	int cnt=0;
	for(int i=1;i<=n;i++) if(cut[i]) cnt++;
	printf("%d\n",cnt);//割点的数量
	for(int i=1;i<=n;i++) if(cut[i]) printf("%d ",i);//每个割点的编号
	return 0;
}

求点双连通分量的个数以及每个点双连通分量的大小以及每个点双连通分量包含哪些点

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+10,M=2e6+10;
struct edge{
	int x,y,pre;
}a[M*2];
int alen,last[N];
void ins(int x,int y)
{
	a[++alen]={x,y,last[x]};
	last[x]=alen;
}
int dfn[N],low[N],id,root;
vector<int> dcc[N];
int cnt;
stack<int> sta;
void tarjan(int x)
{
	low[x]=dfn[x]=++id;
	if(x==root&&!last[x]) return dcc[++cnt].push_back(x);
    sta.push(x);
	for(int k=last[x];k;k=a[k].pre)
	{
		int y=a[k].y;
		if(!dfn[y])
		{
			tarjan(y);
			low[x]=min(low[x],low[y]);
			if(low[y]>=dfn[x])
			{
				cnt++;
				int z;
				do
				{
					z=sta.top();
					sta.pop();
					dcc[cnt].push_back(z);
				} while(z!=y);
				dcc[cnt].push_back(x);
			}
		}
		else low[x]=min(low[x],dfn[y]);
	}
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		if(x==y) continue;
		ins(x,y),ins(y,x);
	}
	for(int i=1;i<=n;i++) if(!dfn[i]) root=i,tarjan(i);
	printf("%d\n",cnt);//点双连通分量的数量
	for(int i=1;i<=cnt;i++)
	{
		printf("%d ",(int)dcc[i].size());//当前点双连通分量的大小
		for(auto j:dcc[i]) printf("%d ",j);//当前点双连通分量包含哪些点
		puts("");
	}
	return 0;
}

有向图的tarjan

求出强连通分量的数量以及每个强连通分量的大小以及每个强连通分量包含哪些点

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=1e5+10;
struct edge{
	int x,y,pre;
}a[M];
int alen,last[N];
void ins(int x,int y)
{
	a[++alen]={x,y,last[x]};
	last[x]=alen;
}
int dfn[N],low[N],id;
vector<int> scc[N];
int cnt;
stack<int> sta;
bool v[N];
void tarjan(int x)
{
	low[x]=dfn[x]=++id;
	sta.push(x),v[x]=1;
	for(int k=last[x];k;k=a[k].pre)
	{
		int y=a[k].y;
		if(!dfn[y])
		{
			tarjan(y);
			low[x]=min(low[x],low[y]);
		}
		else if(v[y]) low[x]=min(low[x],low[y]);
	}
	if(low[x]==dfn[x])
	{
		cnt++;
		int y;
		do
		{
			y=sta.top();
			sta.pop(),v[y]=0;
			scc[cnt].push_back(y);
		}while(y!=x);
	}
}
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		ins(x,y);
	}
	for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i);
	printf("%d\n",cnt);//强连通分量的数量
	for(int i=1;i<=cnt;i++)
	{
		printf("%d\n",scc[i].size());//当前强连通分量的大小
		for(auto j:scc[i]) printf("%d ",j);//当前强连通分量包含哪些点
		puts("");
	}
	return 0;
}
posted @   __Star_Sky  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示