并查集判环

关于并查集判环

我们可以使用并查集来判断一个图中是否存在环:

对于无向图来说,在遍历边 ( 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
#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;
}

你可能感兴趣的:(查并集,图论,算法,c++)