最近几日理了理学过的很多oi知识。。。发现不知不觉就有很多的知识忘记了。。。

在聊聊并查集的时候顺便当作巩固吧。。。。

什么是并查集呢?

( Union Find Set ) 是一种用于处理分离集合的抽象数据结构类型。

具体一点:

  当我们给出两个元素的一个无序对(a,b)时,需要快速合并a和b所在的集合,这期间需要反复查找出某元素所在的集合,“并”、“查”和“集”三字由此而来。也就是说,并查集的作用是动态地维护和处理集合元素之间的复杂关系。

  在并查集中,n个不同的元素被分为若干组,每组是一个集合,这种集合就叫做“分离集合”。并查集支持查找一个元素所属的集合以及两个元素各自所属集合的合并操作。

例如,我们有这样一个问题:

  一个城镇里居住着n个市民,已知一些人互为朋友,而且朋友的朋友也是朋友,也就是说,如果A和B是朋友,C和B是朋友,则A和C也是朋友,请你根据给出的若干组朋友关系,求出最大的一个朋友圈的人数。

  这就有了并查集的用武之地了,一开始我们把所有人都各自放在一个集合中,然后根据依次给出的朋友关系,查找判断两个人是否属于同一个集合(是否已经是朋友),如果不在同一个集合,则将这两个集合合并成一个集合(行成一个朋友圈),最后看哪个集合的元素最多并输出个数即可。

然而并查集有什么主要操作呢?

  使用并查集首先要记录一组分离的动态集合S = {S1,S2,···,Sn},每个集合还要设置一个代表来识别,代表只是要选择该集合中的某个元素即可,哪一个元素被选作代表是无所谓的,重要的是,如果请求某一动态集合的代表两次,且在两次请求间不修改集合,则两次得到的答案应该是相同的。并查集主要有三种操作:初始化、查找与合并。

  (1)初始化:make-set(x)

  建立一个新的集合,其仅有的成员是x(同时就是代表)。由于各集合是分离的,所以要求x在没有其他集合中出现过。使用并查集前都需要执行一次初始化操作,无论采用何种实现方式,其时间复杂度都是O(n)。

  (2)查找:find-set(x)

  查找一个元素所在的集合,本操作返回一个包含x的集合的代表。查找是并查集的核心操作,也是优化并查集效率的重点。

  (3)合并:merge(x,y)

  将包含x和y的动态集合(假设为Sx和Sy)合并成一个新的集合S,本操作返回集合Sx∪Sy的代表。一般来说,在不同的实现中通常以Sx或者Sy的代表作为新集合的代表。合并之前一般要先判断两个元素是否属于同一集合,这可以通过查找操作来实现。

终于到了并查集的实现了!!

  并查集可以采用数组、链表和树三种数据结构来实现,选择不同的实现方式会给查找操作和合并操作的效率带来很大的差别。

并查集的数组实现:

  实现并查集的最简单的方法就是用数组记录每个元素所属集合的编号,A[i] = j 表示元素i属于第j 类集合,初始化A[i] = i。查找元素所属的集合时,只需读出数组中记录的该元素所属集合的编号A[i],时间复杂度为O(1)。合并两个元素各自所属集合时,需要将数组中属于其中一个集合的元素所对应的数组元素值全部更新为另一个集合的编号值,时间复杂度为O(n)。所以用数组实现并查集是最简单的方法,而且容易理解,实际使用较多。但是,合并操作的代价太高,在最坏的情况下,所有集合合并成一个集合的总代价会达到O(n2)。

并查集的链表实现:

  用链表实现并查集也是一种很常见的手段。每个分离集合对应一个链表,链表有一个表头,每个元素有一个指针指向表头,表明了它所属集合的类别,另设一个指针指向它的下一个元素,同时为了方便实现,再设一个指针last表示链表的表尾。

  因为并查集问题处理的对象往往都是连续的整数,所以一般选择用静态数组来模拟链表,用下标对应集合的元素。具体数据结构体定义如下qwq:

struct node{
int head,next,last;
}S[maxn];

  

  此时,初始化和查找操作的实现就很简单了。

make-set(x){
S[x].head = x;
S[x].next = 0;
}
find-set(x){
return S[x].head;
}

  对于合并操作,我们先假设merge(x,y)的参数是有序的,是把y所属的集合合并到x所在的集合。首先执行查找操作,当出现find-set(x)≠ find-set(y)时,直接将y的表头接到x的表尾,同时将y所在集合的所有元素head值设为find-set(x),x的表尾也设为y的表尾。需要注意的是,last指针只要在表头结点中记录即可,因为每一次查找到find-set(x)都可以得到表头元素,而链表中其他元素记录last值是毫无意义的。

  考虑到输入数据的特殊性,根据以上合并方法,我们总是把y接到x后面,如果y所在的集合非常大,每次复制的代价就会非常高,比如输入数据形如:(2,1),(3,1),(4,1),·····,(n,1),显然y所在的集合就会越来越庞大,此时时间复杂度就会达到O(n2)。不过,我们可以很快滴想到一个优化方法:不妨比较x和y所在集合的大小,把较短的链表接在较长的链表尾部,这样效果是一样的,但时间效率肯定不比原来差。具体实现时可以在node里多设一个number域,用来记录此条链表中成员的个数。显然,number记录在表头元素中即可。将两个链表合并的时候,只需要将链表的number域相加,因此维护起来是非常方便的。这种快速实现的方法称为“加权启发式”合并,这里的权就是指number域。假设有n个元素,则可以证明这种方法合并操作的总次数不超过nlog2n次。

merge(x,y){
x = find-set(x);
y = find-set(y);
if(x.number > y.number)
merge(x,y);
merge(y,x);
}

  

  以上是并查集的两种实现方法qwq。然而最最最重要以及实用的是并查集的树实现。我会在  谈一谈并查集QAQ(下) 中仔细讲解qwq。

  

谈一谈并查集QAQ(上)的更多相关文章

  1. Hdu 2473(并查集删除操作) Junk-Mail Filter

    有木有非常吊 加强 加强版   啊  ,看了都不敢做了   .后来先做了食物链这个我还是看过的.但还是A不掉,没明确神魔意思 .总而言之.大牛的博客是个好东西.我就那么看了一下,还是不懂怎莫办啊,哎, ...

  2. BZOJ4025 二分图 分治 并查集 二分图 带权并查集按秩合并

    原文链接http://www.cnblogs.com/zhouzhendong/p/8683831.html 题目传送门 - BZOJ4025 题意 有$n$个点,有$m$条边.有$T$个时间段.其中 ...

  3. BZOJ 3319: 黑白树 树+并查集+未调完+神题

    Code: #include<bits/stdc++.h> #define maxn 1000003 using namespace std; char *p1,*p2,buf[10000 ...

  4. Gym - 100625G Getting Through 计算几何+并查集

    http://codeforces.com/gym/100625/attachments/download/3213/2013-benelux-algorithm-programming-contes ...

  5. BZOJ 4195: [Noi2015]程序自动分析 [并查集 离散化 | 种类并查集WA]

    题意: 给出若干相等和不等关系,判断是否可行 woc NOI考这么傻逼的题飞快打了一个种类并查集交上了然后爆零... 发现相等和不等看错了异或一下再叫woc90分 然后发现md$a \neq b, a ...

  6. luogu2024 食物链 (并查集)

    把一个点拆成三个,分别对应它的同类.它的猎物和它的天敌,这样的话(以下的相等都是并查集意义上的): 如果令a,b同类,那么a的猎物不能是b的同类,a的天敌不能是b的同类 如果令a吃b,那么a的同类不能 ...

  7. 种类并查集,Poj(1703)

    题目链接:http://poj.org/problem?id=1703 第一次做种类并查集,有的地方还不是很清楚,想了一上午,有点明白了,这里记录一下. 这里我参考的红黑联盟的题解. 关键:种类并查集 ...

  8. poj1703 Find them,Catch them 【并查集】

    做过一些的带权并查集,再来做所谓的"种类并查集",发现好像就顿悟了. 种类并查集与带权并查集实质上的区别并不大. 关键的区别就是种类并查集仅仅是带权并查集再弄个%取余操作而已.然后 ...

  9. HDU3038 How Many Answers Are Wrong —— 带权并查集

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=3038 How Many Answers Are Wrong Time Limit: 200 ...

随机推荐

  1. 【C 语言】一元二次方程

    求一元二次方程:ax2+bx+c=0 的根. 输入三个实数a,b,c的值,且a不等于0. 数学基础:一元二次方程 只含有一个未知数(一元),并且未知数项的最高次数是2(二次)的整式方程叫做一元二次方程 ...

  2. codeforces div2 603 D. Secret Passwords(并查集)

    题目链接:https://codeforces.com/contest/1263/problem/D 题意:有n个小写字符串代表n个密码,加入存在两个密码有共同的字母,那么说这两个密码可以认为是同一个 ...

  3. Java“被迫”退出争霸,Python继续霸占首位!老牌程序员:我不服

    2019年转眼已经接近尾声,如果盘点下2019年最火的语言,除了Python还能有谁?你心中的王者语言又是谁? 这一年Python风光无限 这一年JAVA走向右边 这一年,我们都很感慨,你呢? 关于P ...

  4. AcWing 840. 模拟散列表

    拉链法 #include<cstring> #include<iostream> using namespace std ; ; int h[N],e[N],ne[N],idx ...

  5. 2.5 【配置环境】多浏览器驱动 (chrome、IE、Firefox)❀

    来源:http://blog.csdn.net/huilan_same/article/details/51896672 http://www.cnblogs.com/thinkCoding/p/64 ...

  6. 【PAT甲级】1104 Sum of Number Segments (20 分)

    题意:输入一个正整数N(<=1e5),接着输入N个小于等于1.0的正数,输出N个数中所有序列的和. AAAAAccepted code: #define HAVE_STRUCT_TIMESPEC ...

  7. flask 2 进阶

    # 创建项目 jinja2 语法基础 # pycharm 里面 创建 new project -->pure python 之后选择路径 选择解释器 以及虚拟环境问题 from flask im ...

  8. 【Python collections】

    目录 namedtuple deque Counter OrderedDict defaultdict "在内置数据类型(dict.list.set.tuple)的基础上,collectio ...

  9. 洛谷 P3901 数列找不同(莫队)

    题目链接:https://www.luogu.com.cn/problem/P3901 这道题简单莫队模板题,然后$add$和$del$分别处理$vis[]$从$0-->1$和从$1--> ...

  10. shell脚本自学之路

    阿里云大学教学https://edu.aliyun.com/course/155/ 运行 chmod +x xx.sh ./xx.sh 基本语法:echo  输出  $赋值 特殊变量: $* 变量的使 ...