tarjan算法求割点

图论:求割点(无向图中的概念)

回边:dfs过程中遇到已访问节点所经过的边观察dfs树,有两类节点可成为割点。

对非叶子节点u,若子树节点均无指向u的祖先节点的回边,说明删除u后,根节点与u的子树不在连通,则u为割点。


dfsn[u]记录u节点的dfs序号。

low[u]记录节点u或u的子树能追溯到的最早祖先

当(u,v)为树边,且low[to]>=dfsn[from],节点from为割点。

对于上图,割点为2跟3。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=10;
int* node;
int dfsn[MAXN],low[MAXN],c=0;
bool vis[MAXN];
struct edge{
	int to,next;
	edge(){}
	edge(int v,int w):to(v),next(w){}
};
edge e[MAXN*2];
void tarjan(int from){
	static int cnt=0;
	vis[from]=true;
	dfsn[from]=low[from]=cnt++;
	for(int i=node[from];i+1;i=e[i].next){
		int to=e[i].to;
		if(!vis[to]){
			tarjan(to);
			low[from]=min(low[from],low[to]);
			if(from!=0&&low[to]>=dfsn[from]){
				printf("%d ",from);
			}
		}else{
			low[from]=min(low[from],dfsn[to]);
		}
	}
}
void addEdge(int from,int to){
	e[c].to=to;
	e[c].next=node[from];
	node[from]=c++;
}
int main(){
	freopen("./in.txt","r",stdin);
	node=new int[MAXN];
	int n,u,v;
	memset(node,-1,MAXN*sizeof(int));
	memset(vis,false,sizeof(vis));
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d%d",&u,&v);
		addEdge(u,v);
		addEdge(v,u);
	}
	tarjan(0);
	return 0;	
}


如何判断根节点是割点呢?dfs一个方向的话会访问所有的点,如果存在根节点访问了两个子节点,那么就说明有两个区域,也就是生成树上有两个子树

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN=10;
int* node;
int dfsn[MAXN],low[MAXN],c=0;
bool vis[MAXN];
struct edge{
	int to,next;
	edge(){}
	edge(int v,int w):to(v),next(w){}
};
edge e[MAXN*2];
void tarjan(int from){
	static int cnt=0;
	int child=0;
	vis[from]=true;
	dfsn[from]=low[from]=cnt++;
	for(int i=node[from];i+1;i=e[i].next){
		int to=e[i].to;
		if(!vis[to]){
			child++;
			tarjan(to);
			low[from]=min(low[from],low[to]);
			if(from!=3&&low[to]>=dfsn[from]){
				printf("%d ",from);
			}
		}else{
			low[from]=min(low[from],dfsn[to]);
		}
	}
	if(child>=2){
		printf("%d\n",from);
	}
}
void addEdge(int from,int to){
	e[c].to=to;
	e[c].next=node[from];
	node[from]=c++;
}
int main(){
	freopen("./in.txt","r",stdin);
	node=new int[MAXN];
	int n,u,v;
	memset(node,-1,MAXN*sizeof(int));
	memset(vis,false,sizeof(vis));
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d%d",&u,&v);
		addEdge(u,v);
		addEdge(v,u);
	}
	tarjan(3);
	return 0;	
}


in.txt

8
0 1
1 2
2 3
0 3
3 4
3 5
4 5
2 6


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值