并查集判环(无向图)

该博客介绍了如何使用并查集来检测无向图中的环,并判断图是否连通。在遍历边时,若发现连接的两个节点已经在同一连通块中,则存在环。此外,通过比较顶点数和边数可以确定连通块的环个数。提供的代码示例展示了如何实现这一过程,并解决了一道相关题目:判断每个连通块环的个数是否为1以及图是否连通且无环。

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

关于并查集判环

我们可以使用并查集来判断一个图中是否存在环(此方法仅在无向图中正确):

对于无向图来说,在遍历边 ( u − > v ) (u->v) (u>v) 时,如果结点 u u u 和结点 v v v 的“父亲”相同,那么结点 u u u 和结点 v v v 在同一个环中。

判断无向图是否有环,只需要在合并时加判断即可
每出现一次连接两个已经连通的顶点,图中就会多一个环

而DFS判无向图中连通块环的个数,可以通过点数和边数的个数来判断
设点数 V V V,边数 E E E,如果 V = E + 1 V=E+1 V=E+1,那么就无环, V = E V=E V=E 就是一个环,依次…

例题

1.判断每个连通块环的个数是否为一个
(每个连通块满足顶点和边数相等

2.小希的迷宫
题意:
判断所给图是否连通无环,满足输出 “Yes”,否则输出 “No”
思路:
并查集判断连通并且无环即可
code:

#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define ld long double
#define all(x) x.begin(), x.end()
#define eps 1e-6
using namespace std;
const int maxn = 1e5 + 9;
const int mod = 998244353;
ll n, m;
int f[maxn];
int x, y;
bool flag = 0;
int find(int x)
{
	int r = x, j, k = x;
	while(r != f[r]) r = f[r]; // 寻找根节点 
	while(k != r)  
	{
		j = f[k];  // 暂存此时k的父节点 
		f[k] = r;  //  将k的父节点改为根节点 
		k = j;  //  k移到父节点   直至全改为根节点  
	}
	return r;
}
void merge(int fx, int fy){
	fx = find(fx); fy = find(fy);
	if(fx != fy) f[fx] = fy;
	else flag = 1;// 连接了两个已经连通的顶点,说明会形成环
}
unordered_map<int,int> ma;
void work()
{
	if(x == 0 && y == 0){// 空图输出Yes 
		cout << "Yes\n";return;
	}
	for(int i = 1; i <= 1e5; ++i) f[i] = i;
	ma[x] = ma[y] = 1;
	merge(x, y);
	while(cin >> x >> y && x != 0){
		ma[x] = ma[y] = 1;
		merge(x, y);
	}
	set<int> se;// 所有出现的顶点的父节点塞进set
	for(int i = 1; i <= 1e5; ++i) if(ma[i])
	{
		int p = find(i);
		se.insert(p);
	}
	if(!flag && se.size() == 1) cout << "Yes\n";
	else cout << "No\n";
	ma.clear();
	flag = 0;
}

int main()
{
	ios::sync_with_stdio(0);
	while(cin >> x >> y && x != -1)
	work();
	return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值