Tarjan_割点

无向图的割点

割点:如果删去一个点以及相关的边,图变为不连通,则称这个点为割点


割点条件 1 or 2

1.(树)根结点u,有两个或者多个子结点(子树)

2.非(树)根结点u,存在边(u,v),使得v和所有后代都没有反向边可以连回 u 的祖先,即low[v]>=dfn[u]


以下割点代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <set>
using namespace std;
const int MAXN=100010;
int n,m,nume,depth,ans;
int head[MAXN],low[MAXN],dfn[MAXN],fa[MAXN];
bool iscut[MAXN];
struct Edge
{
	int nex,to;	
}e[MAXN*2]; 
int in()
{
	int x=0,flag=1;
	char ch=getchar();
	while (ch<'0'||ch>'9') {if (ch=='-') flag=-1;ch=getchar();}
	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*flag;
}
void addedge(int from,int to)
{
	e[++nume]=(Edge){head[from],to};
	head[from]=nume;
}
void tarjan(int u)
{
	int child=0;
	low[u]=dfn[u]=++depth;
	for (int i=head[u];i;i=e[i].nex)
	{
		int v=e[i].to;
		if (!dfn[v])
		{
			child++;
			fa[v]=u;
			tarjan(v);
			low[u]=min(low[u],low[v]);
			if ((low[v]>=dfn[u]&&fa[u]!=u)||(child>1&&fa[u]==u)) 
			{
				if (!iscut[u]) ans++;
				iscut[u]=true;
			}
			//if (low[v]>dfn[u]) 桥 
		}
		else
		{
			if (u!=fa[v]) 
				low[u]=min(low[u],dfn[v]); 
		}
	}
}
int main()
{
	n=in(),m=in();
	for (int i=1;i<=m;i++)
	{
		int u=in(),v=in();
		addedge(u,v);
		addedge(v,u);	
	}
	for (int i=1;i<=n;i++) fa[i]=i;
	for (int i=1;i<=n;i++)
		if (!dfn[i]) tarjan(i);
	printf("%d\n",ans);
	for (int i=1;i<=n;i++)
		if (iscut[i]) printf("%d ",i);
	return 0;		
}

猜你喜欢

转载自blog.csdn.net/wangyc123456/article/details/80208698
今日推荐