这篇文章只是针对于初学者的简单入门,后续会不定期深入更新一些高级数据结构的知识,结合例题帮助各位码友理解。
并查集简介
并查集(DisjointSet)是一种精巧而实用的数据结构,它主要用于处理一些不相交集合的合并问题。经典的应用有连通图、最小生成树Kruskal算法、最近公共祖先(LeastCommonAncestors,LCA)等。并查集在算法竞赛中极为常见。
通常用“帮派”的例子说明并查集的应用场景。一个城市中有n个人,他们分成不同的帮派。同属于一个帮派的人相互之间是朋友,朋友的朋友是朋友。给出一些人的关系,如1号和2号是朋友,1号和3号也是朋友,那么他们都属于一个帮派。在分析完所有朋友关系之后,问有多少帮派,每人属于哪个帮派。给出的n=10^6。
我们可以先思考暴力法以及复杂度。如果用并查集实现,不仅代码很简单,而且查询的复杂度小于O(log2^n)。
并查集的概念:将编号分别为1~n的n个对象划分为不相交集合,在每个集合中,选择其中某个元素代表所在集合。
并查集的基本操作
1.初始化
定义数组s[ ],s[i]是元素i所属的并查集,开始时,还没有处理点与点之间的朋友关系,所以每个点属于独立的集,直接以元素i的值表示它的集s[i],如元素1的集s[1]=1。如图所示,左图给出了元素与集合的值,右图画出了逻辑关系。为了便于讲解,左图区分了节点i和集s,把集的编号加上了下画线;右图用圆圈表示集,用方块表示元素。
2.合并
(1)加入第1个朋友关系(1,2)。在并查集s中,把节点1合并到节点2,也就是把节点1的集1改为节点2的集2,如图所示。
(2)加入第2个朋友关系(1,3)。查找节点1的集2,再递归查找节点2的集2,然后把节点2的集2合并到节点3的集3。此时,节点1、2、3都属于一个集。如图所示,为简化图示,把节点2和集2画在了一起。
(3)加入第3个朋友关系(2,4)。结果如图所示,请大家自己分析。
3.查找
上述步骤中已经有查找操作。查找元素的集,是一个递归的过程,直到元素的值和它的集相等,就找到了根节点的集。可以看到,这棵搜索树的高度可能很大,复杂度为O(n),变成了一个链表,出现了树的退化”现象。
4.统计
如果,s[i]=i,这是一个根节点,是它所在的集的代表;统计根节点的数量,就是集的数量。下面用一道蓝桥杯国赛真题《合根植物》给出并查集基本操作的代码。
具体样例说明还请各位移步至官网参考,在此就不过多赘述。
这道题如果在没有掌握并查集的前提下来做,还是比较复杂的,我也是学过很久之后没有什么印象了,就先试了一下普通解法,但做起来确实很麻烦。但如果有并查集的思想,那么这道题就很简单了。
不会并查集的同学可以学习一下,它在算法竞赛中还是很常见的,连通图、最小生成树、LAC等等都会应用到并查集。
这道题中主要的思路就是对于每一次给出的两个需要合根的植物,都将前一个植物所属的集合标号修改为后一个植物所属的集合,或者说是将前一个植物的集合指向后一个植物的集合,对于所有数据这样操作,最终我们可以得到若干棵搜索树,这些搜索树的高度可能会非常高,但最终都会有一个根节点,而且这个根节点的标号和他对应的植物的序号一定是相等的,我们最后只需要遍历所有植物所属的集合,找到集合标号和植物序号相等的数量,这就是合根后得到的合根植物的数量。
虽然说我们这里将合根后的结果叫做搜索树,但其实将它视作链表理解起来会容易很多,即每一个植物的标号都是数据域,集合则是指针域,指向这个数据域所属的集合。
#include<bits/stdc++.h>
using namespace std;
const int SIZE=1000001;
int N[SIZE],ans=0;
void init_set(int s)//初始化
{
for(int i=1;i<=s;++i) N[i]=i;
}
int find_set(int a)//查找
{
return a == N[a] ? a : find_set(N[a]);
}
void merge_set(int a,int b)//合并
{
a=find_set(a); b=find_set(b);
if(a!=b) N[a]=N[b];//把a合并到b上,b的根成为a的根
}
int main()
{
int m,n,k,a,b;
cin >> m >> n >> k ;
init_set(m*n);
while(k--){
cin >> a >> b;
merge_set(a,b);//合并a,b
}
for(int i=1;i<=m*n;++i){//统计有多少个集
if(N[i]==i) ans++;
}
cout << ans << endl;
return 0;
}
以上只是并查集的初步入门,后续还有合并优化、路径压缩、带权并查集等,用于解决图论中的基本问题非常方便。
希望可以对大家有帮助。