无重边连通无向图求割点和桥

本文介绍了无向连通图中的割点与桥的概念,并详细解释了如何利用DFS算法进行判定的方法。通过定义dfn和low两个关键状态,文章给出了判断割点与桥的具体条件,并提供了实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.割点和桥

 无向连通图中,如果删除某点后,图变
成不连通,则称该点为割点。
 
 无向连通图中,如果删除某边后,图变
成不连通,则称该边为桥。

所以说啊,割点和桥这个概念的应该范围应该只是在无向连通图中的!这一点要十分注意!

二.怎样判定

dfn[u]定义和前面类似,但是low[u]定义为u
或者u的子树中能够通过非父子边(父子边
就是搜索树上的边)追溯到的最早的节点
的DFS开始时间

一个顶点u是割点,当且仅当满足(1)或(2)
 
(1) u为树根,且u有多于一个子树。
(2) u不为树根,且存在(u,v)为树枝边(或称父子
边,即u为v在搜索树中的父亲),使得
dfn(u)<=low(v)。
 
一条边(u,v)是桥,当且仅当(u,v)为树枝边,且
满足dfn(u)<low(v)(前提是其没有重边)

然后我们只需要根据这个思路去写程序就好啦!

三.思路解析

根据上面的两条定理我们知道我们只要知道每个点的dfn和low那么我们不难判定这个点是否是割点,那么下一步当然就是根据low,dfn的定义去求这连个状态就好啦,那么当然为了求low我们自然要求dfs了,这里和原来的tarjan有所不同的是我们缺少了vis这个状态也没有栈这个结构,那么是为什么呢,

#include <iostream>
#include <cstring>
#include <cstdio>
#include <stack> 
#include <vector>
using namespace std;
const int maxn=100000;
int cv[maxn],n,m,fa[maxn],index,dfn[maxn],low[maxn];
stack <int> st;
vector <int> map[maxn];
int min(int a,int b)
{
	if(a<b) return a;
	else return b;
}
void tarjan(int u,int father)
{
	index++;
	dfn[u]=low[u]=index;
	fa[u]=father;
	for(int i=0;i<map[u].size();i++)
	{
		int v=map[u][i];
		if(!dfn[v])
		{
			tarjan(v,u);
			low[u]=min(low[u],low[v]);
		}
		else if(v!=father)  
			low[u]=min(low[u],dfn[v]);
	}
}
void count()
{
	int rootson=0;
	for(int i=2;i<=n;i++)
	{
		int v=fa[i];
		if(v==1) rootson++;
		else if(low[i]>=dfn[v]) cv[v]=1;
	}
	if(rootson>1) cv[1]=1;
	for(int i=1;i<=n;i++)
		if(cv[i]) printf("%d\n",i);
	for(int i=2;i<=n;i++)
	{
		int v=fa[i];
		if(dfn[v]<low[i])
		{
			printf("%d,%d\n",v,i);
		}
	}
}

void init()
{
	index=0;
	while(!st.empty()) st.pop();
	memset(cv,0,sizeof(cv)); 
	memset(dfn,0,sizeof(dfn));
	memset(low,0,sizeof(low));
	memset(fa,0,sizeof(fa));
	for(int i=0;i<maxn;i++) map[i].clear();
}
int main()
{
	freopen("input.txt","r",stdin);
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		init();
		for(int i=1;i<=m;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			map[u].push_back(v);
			map[v].push_back(u);
		}
		tarjan(1,0);
		count();
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值