编程奇境:C++之旅,从新手村到ACM/OI算法竞赛大门(中级武器:并查集)

我们都知道,朋友的朋友也可以是朋友,并查集就是这么一种武器,能够让自己广交天下之友。

并查集

并查集啊,想象一下你班上的同学们都在操场上自由活动。突然老师说:"大家找朋友手拉手围成圈玩个游戏!"这时候,每个同学就得赶紧找到其他同学牵手,形成一个个的小圈子。

一开始,可能有的同学很快就找到了朋友,两个人就形成了一个小小的圈子;有的同学可能慢一点,但他们最终也会找到别人,加入到已有的圈子或者和新找到的朋友形成新的圈子。在这个过程中,如果两个小圈子碰到了,他们就可以选择合并成一个更大的圈子。

并查集,就是在计算机里帮助我们管理这种"找朋友拉手组成圈子"的一种数据结构。它主要有两个任务:一个是"查询"(find),就是看看某个同学属于哪个圈子;另一个是"合并"(union),就是把两个圈子合在一起变成一个大圈子。

举个例子,假如你想要知道小明和小红是不是在一个圈子里玩,你就可以用并查集的"查询"功能,很快得出答案。如果小明和小红不在同一个圈子里,但你想让他们一起玩,就可以用"合并"功能,让他们的圈子连起来。

简单来说,并查集就像是一个班级里的"牵手管理员",帮助我们知道谁和谁是一伙的,还能轻松地把不同的小组组合成更大的团队,特别适合处理一些需要不断合并和查询团体归属的问题。

举个栗子

第一行包含两个整数 𝑁,𝑀,表示共有 𝑁个元素和 𝑀个操作。

接下来 𝑀行,每行包含三个整数 𝑍𝑖,𝑋𝑖,𝑌𝑖​。

当 𝑍𝑖=1时,将 𝑋𝑖与 𝑌𝑖所在的集合合并。

当 𝑍𝑖=2 时,输出 𝑋𝑖与 𝑌𝑖是否在同一集合内,是的输出 Y ;否则输出 N

cpp 复制代码
#include<iostream>
using namespace std;
int f[200005];
//并查集模板 
int find(int x)
{
	if (f[x] == x)//如果组长是自己 
	{
		return x;//直接返回 
	}
	f[x] = find(f[x]);//递归地找组长 
	return f[x];
}
void merge(int u, int v)//合并 
{
	f[v] = u;//把v这个组归到u这个组里 
}
int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		f[i] = i;//初始化 每个人的组长都是自己 
	}
	for (int i = 0; i < m; i++)
	{
		int z;
		int x, y;
		cin >> z >> x >> y;
		int u = find(x);//寻找组长 
		int v = find(y);
		if (z == 1)//如果可以合并 
		{
			merge(u, v);
		}
		else if (z == 2)//查找 
		{
			if (find(x) == find(y)) {//看看是否是同一个组的 
				cout << "Y" << endl;
			}
			else
			{
				cout << "N" << endl;
			}
		}
	}
	return 0;
}

应用场景

并查集这种数据结构虽然简单,但它在很多实际问题中非常有用,尤其擅长处理涉及分类、归属判断和动态集合合并的问题。以下是并查集的一些典型应用场景:

  1. 社交网络的朋友圈问题:在社交网络中,如果要判断两个人是否是朋友或者间接朋友(通过共同的朋友连接),可以使用并查集来高效地管理和查询这些关系。

  2. 图的连通性问题:在无向图中,判断两个顶点是否连通,或者统计连通分量的数量时,可以用并查集快速实现。

  3. 赛事安排问题:如果有比赛需要避免某些特定队伍在早期相遇(比如来自同一地区的队伍),可以通过构建并查集来确保不会安排这样的对阵。

  4. 文件系统管理:在操作系统中,用来管理文件和目录的层次结构,判断两个文件是否位于同一个目录下。

  5. 最小生成树算法中的 Cycle Detection(环检测):如Kruskal算法中,用于检测添加一条边是否会形成环。

  6. 游戏开发中的团队管理:在多人在线游戏中,快速合并和查询玩家的队伍状态。

  7. 文本处理中的名词消歧:在自然语言处理中,识别文本中的名词是否指代同一实体,有助于实现命名实体识别的优化。

  8. 网络路由问题:在网络设计中,确定数据包从源到目的地是否有可达路径,或者在路由表合并时避免循环。

并查集的高效之处在于它支持近乎常数时间的查询和合并操作,这使得它成为解决上述问题的有力工具。在很多情况下,通过巧妙地使用并查集,可以大大简化算法的设计和实现。

练习题

P3367 【模板】并查集 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P1551 亲戚 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P1111 修复公路 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P1195 口袋的天空 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P1396 营救 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P1892 [BOI2003] 团伙 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P1621 集合 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

P2294 [HNOI2005] 狡猾的商人 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

百看不如一练,只有实践才是进步最快的方式,更要独立思考,如果想不出来了就看题解,会有眼前一亮的感觉。好啦,今天就到这里吧。下一期再见,记得给专栏点个关注,明天接着来哦~

相关推荐
记录成长java31 分钟前
ServletContext,Cookie,HttpSession的使用
java·开发语言·servlet
前端青山31 分钟前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
青花瓷34 分钟前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode
睡觉谁叫~~~35 分钟前
一文解秘Rust如何与Java互操作
java·开发语言·后端·rust
音徽编程36 分钟前
Rust异步运行时框架tokio保姆级教程
开发语言·网络·rust
观音山保我别报错36 分钟前
C语言扫雷小游戏
c语言·开发语言·算法
小屁孩大帅-杨一凡1 小时前
java后端请求想接收多个对象入参的数据
java·开发语言
m0_656974742 小时前
C#中的集合类及其使用
开发语言·c#
java1234_小锋2 小时前
使用 RabbitMQ 有什么好处?
java·开发语言
wjs20242 小时前
R 数据框
开发语言