【算法训练营】并查集见解与实现

导入

老伙计,如果我问一个问题,你爷爷的女儿的姐姐的表妹的儿子你爷爷的儿子的表弟的姐姐的女儿有没有血缘关系(其中关系都是血亲关系),你会怎么判断?
需要画一棵负责的家族图谱树来判断吗?
不需要!
可以很快判断出来,他们是有血缘关系的,因为他们都有一个共同的祖宗——你的爷爷。
这就是并查集(Union-find set)的核心思维。

理解

定义:
并查集,在一些有N个元素的集合应用问题中,我们通常是在开始时让每个元素构成一个单元素的集合,然后按一定顺序将属于同一组的元素所在的集合合并,其间要反复查找一个元素在哪个集合中。这一类问题近几年来反复出现在信息学的国际国内赛题中。其特点是看似并不复杂,但数据量极大,若用正常的数据结构来描述的话,往往在空间上过大,计算机无法承受;即使在空间上勉强通过,运行的时间复杂度也极高,根本就不可能在比赛规定的运行时间(1~3秒)内计算出试题需要的结果,只能用并查集来描述。(来自百度)
我的理解:并查集解决的问题是,在一个错综复杂的可传递的关系中,通过指定同一祖宗的方式,过滤了在该情景下无用的中间关系,实现了信息的提炼。


C++实现

环境:
系统:
win10
IDE:Visual Studio 2022


//输入第一行:关系数n
//后续n行输入关系
//输出为集合数
//Ufset的中5代表并查集的大小,可以根据情景自行修改。
//关系输入要统一升序或降序,如:1 2/2 3不可1 2/3 2
#include<iostream>
#include<string>
using namespace std;

class UfSet {
private:
	int size=5;
	int fa[5];
public:
	UfSet(int n);
	void init();
	void Union(int x, int y);
	int Find(int z);
	int Count();

};
UfSet::UfSet(int n) {
	for (int i = 0; i < size; i++)
	{
		fa[i] = i;
	}

}

void UfSet:: init() {

}

int UfSet::Find(int z) {

	if (z != fa[z]) {
		fa[z] = Find(fa[z]);
		return fa[z];
	}
	else {
		return fa[z];
	}
}

int UfSet::Count() {
	int ans=0;
	for (int i = 0;i < 5;i++) {
		if (i == fa[i]) {
			ans++;
		}
	}
	return ans;
}

void UfSet::Union(int x, int y) {
	int _x = x;
	int _y = y;
	int a = Find(_x);
	int b = Find(_y);
	if (a != b) {
		fa[b] = a;
	}
}


int main()
{
	//Union-Find Set 大小
	UfSet ufset(5);
	//输入的关系数
	int n;
	cin >> n;

	while (n--) {
		int x, y;
		cin >> x;
		cin>> y;
		ufset.Union(x, y);

	}

	cout << ufset.Count() << endl;
	
    return 0;
}



谢谢你的阅读

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Beta-Zero

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值