并查集.ppt

上传人:b****2 文档编号:2679536 上传时间:2022-11-07 格式:PPT 页数:40 大小:60.50KB
下载 相关 举报
并查集.ppt_第1页
第1页 / 共40页
并查集.ppt_第2页
第2页 / 共40页
并查集.ppt_第3页
第3页 / 共40页
并查集.ppt_第4页
第4页 / 共40页
并查集.ppt_第5页
第5页 / 共40页
点击查看更多>>
下载资源
资源描述

并查集.ppt

《并查集.ppt》由会员分享,可在线阅读,更多相关《并查集.ppt(40页珍藏版)》请在冰豆网上搜索。

并查集.ppt

并查集并查集是一种树型的高级数据结构,主要用于处理不相交集合的合并及查询问题。

它在计算机科学中有着广泛的应用,例如求解最小生成树、亲戚关系的判定、确定无向图的连通子图个数、最小公共祖先问题等,都要用到并查集。

集合集合是数学中最基本的构造之一,将一组满足某种性质的对象放在一起就形成了集合。

集合中包含的对象称为集合中的元素,集合中的元素是无序而且唯一的。

人们常用大写英文字母A、B、C等来表示集合,并用xA来表示x是集合A中的元素。

集合的并、交、差:

由A、B集合的全体元素组成的集合为A与B的并集,记作AUB;A与B的公共元素组成的集合称A与B的交集,记作AB;属于集合A而不属于集合B的元素组成的集合称为A减B的差,记作A-B。

如何实现存储集合中的元素?

由于集合中存放的是一组具有相同性质的对象,一般人很容易想到用数组来存储。

用数组很容易实现集合类型,但要注意:

因为数组一旦定义,其大小就固定不变。

所以在定义的时候,要充分考虑最大空间。

也可以用链表来存储集合元素。

链表可以很容易的动态生成和释放,所以增减节点是很方便的,完全不用考虑象数组那样的长度问题。

删除元素也很方便。

但是因为涉及到指针,实现起来很容易出错。

还可以用vector.它有数组的优点,而且又不必考虑数组那样可能越界的情况。

并查集的概念在某些应用中,我们要检查两个元素是否属于同一个集合,或者将两个不同的集合合并为一个集合。

这是不相交集合经常处理的两种操作:

查找和合并,我们称为并查集。

查找find:

查找一个指定元素属于哪个集合。

对于判断两个元素是否属于同一个集合是非常有用的。

合并union:

将两个集合合并为1个集合。

除了这两个操作之外,还有一个基础的操作makeset,用于建立只有1个元素的集合。

为了更精确的定义上述三个操作,我们需要用一种方法来表示集合。

一种通用的做法是选择集合中某个固定的元素作为集合的代表,让他唯一的标识整个集合。

一般说来,选取的代表是任意的。

也就是说,到底选取集合中的哪个元素作为它的代表是无关紧要的。

在并查集中,我们对于集合的表示利用树的思想,一个集合可以看做一棵树,树根即代表该集合的标识。

如果两个元素在同一个树中,则它们是同一个集合;合并两个集合,即是对两棵树进行合并。

find(x):

返回元素x所属集合的代表。

为了判断任意两个元素x和y是否属于同一个集合,我们只需要判断find(x)和find(y)是否相等即可,如果相等,说明他们属于同一个集合,否则他们不属于同一个集合。

union(x,y):

将包含元素x的集合(假设为Sx)和包含元素y的集合(假设为Sy)合并为一个新的集合(即这两个集合的并集),所得到并集可以用它的任何一个元素来做代表,但在实践中,一般都是选择Sx或Sy的代表作为并集的代表。

makeset(x):

建立一个只包含元素x的集合,显然,此时该集合的代表应该而且只能为x.并查集的实现:

(数组)voidmakeset(x)parentx=-1;parentx表示x的父亲编号.最开始的,每个元素自成一个集合,即每个元素开始都当做一棵树,其父亲节点初始为-1,表示它没有父亲。

intfind(x)/查找x所在的集合。

while(parentx!

=-1)x=parentx;returnx;voidmyunion(intx,inty)intr1=find(x);intr2=find(y);if(heightr1heightr2)numr2=r1;elseif(heightr1heightr2)numr1=r2;elsenumr1=r2;heightr2+;思考:

如何判断最后所有元素是否属于同一个集合?

在以上的实现中,如何更进一步优化?

一个集合即是一棵树,在集合中,父子关系实际并不重要,其作用只是通过父亲找到树的根而已,而根也只是集合的标识,树中的任意节点都可以作根。

在并查集的实现过程中,树的深度是影响速度的一个重要因素。

树的深度越小,则find操作越快,union操作也越快。

在union操作中,我们通过height数组已经尽量避免了树的高度增加。

但是,我们还可以主动让树的高度减小。

改进后的find操作:

intfind(intx)if(parentx!

=-1)parentx=find(parentx);if(parentx=-1)returnx;elsereturnparentx;这是路径压缩。

它可以在find的过程中,让路径上的元素都成为根的儿子节点。

这样,从形式上看,树就从细长型变成了扁平型。

并查集的应用实例亲戚亲戚若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。

规定:

x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。

如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。

第一行:

三个整数n,m,p,(n=5000,m=5000,p=5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。

以下m行:

每行两个数Mi,Mj,1=Mi,Mj=N,表示Ai和Bi具有亲戚关系。

接下来p行:

每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。

输出格式P行,每行一个Yes或No。

表示第i个询问的答案为“具有”或“不具有”亲戚关系。

简单的并查集题目。

动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。

A吃B,B吃C,C吃A。

现有N个动物,以1N编号。

每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。

有人用两种说法对这N个动物所构成的食物链关系进行描述:

第一种说法是“1XY”,表示X和Y是同类。

第二种说法是“2XY”,表示X吃Y。

此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。

当一句话满足下列三条之一时,这句话就是假话,否则就是真话。

1)当前的话与前面的某些真的话冲突,就是假话;2)当前的话中X或Y比N大,就是假话;3)当前的话表示X吃X,就是假话。

你的任务是根据给定的N(1=N=50,000)和K句话(0=K=100,000),输出假话的总数。

食物链(NOI2001)很显然,对假话条件2、3的处理十分简单,只要在读入数据时作两个条件判断即可解决,题目的主要任务在于处理条件1。

从表面上看,条件的处理似乎也没有什么难度:

一个动物无非就是A,B,C三类,而A,B,C之间的食物链关系是一对一单向环形的,也就是说如果已知动物X所属种类和X、Y之间的食物链关系,就一定可以确定出动物Y的种类,同时某个动物具体属于哪一类并不影响本题的结果,而只要求它与其他动物关系的相对位置正确即可。

于是,我们不妨开3个数组A,B,C,分别记录着三种类的成员,首先假设第一句有效话中的动物X为A类,将其放入数组A,倘若Y与X同类,则把Y也放入A;若Y被X吃,则将Y放入B,如此反复操作所有的有效话,就可以确定每个动物的种类,并容易统计出假话的个数。

问题似乎已经圆满地解决了,但是,稍稍认真思考就会发现,上面的这个算法存在着重大的错误,是十分片面的。

对于一个未知属性的生物我们都采取的是定义为A类型,这样子显然是错的。

可见,这个算法只能当每一句话都可直接与此前已知的食物链建立明确关系的时候才能使用。

明确了上面这个关系,我们就不难从刚才的算法扩展出另一种算法:

对于目前关系未知的动物X,我们为他新开辟一条食物链A2,B2,C2,显然,在这个新的组中,动物X所在的种类也是随意的,于是假设它在A2组,这样,所有与X的关系就可用与算法1同样的方式加入这个组中,而这个组与原先的组A1,B1,C1的关系是不确定的。

如此反复,我们也可以得到组3、组4、组5,一旦有一句话牵涉到某两个组的成员之间的食物链关系,我们就依据一定的换算规则将这两个组合并起来,以保证关系网的完整性。

通过上面的分析,并查集在本题中的运用已经呼之欲出。

一个集合有三类的元素,合并集合的时候,需要对三类元素进行合并。

银河英雄传说(NOI2002)公元五八一年,地球居民迁移至金牛座第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展。

宇宙历七九九年,银河系的两大军事集团在巴米利恩星域爆发战争。

泰山压顶集团派宇宙舰队司令莱因哈特率领十万余艘战舰出征,气吞山河集团点名将杨威利组织麾下三万艘战舰迎敌。

杨威利擅长排兵布阵,巧妙运用各种战术屡次以少胜多,难免恣生骄气。

在这次决战中,他将巴米利恩星域战场划分成30000列,每列依次编号为1,2,30000。

之后,他把自己的战舰也依次编号为1,2,30000,让第i号战舰处于第i列(i=1,2,30000),形成“一字长蛇阵”,诱敌深入。

这是初始阵形。

当进犯之敌到达时,杨威利会多次发布合并指令,将大部分战舰集中在某几列上,实施密集攻击。

合并指令为Mij,含义为让第i号战舰所在的整个战舰队列,作为一个整体(头在前尾在后)接至第j号战舰所在的战舰队列的尾部。

显然战舰队列是由处于同一列的一个或多个战舰组成的。

合并指令的执行结果会使队列增大。

然而,老谋深算的莱因哈特早已在战略上取得了主动。

在交战中,他可以通过庞大的情报网络随时监听杨威利的舰队调动指令。

在杨威利发布指令调动舰队的同时,莱因哈特为了及时了解当前杨威利的战舰分布情况,也会发出一些询问指令:

Cij。

该指令意思是,询问电脑,杨威利的第i号战舰与第j号战舰当前是否在同一列中,如果在同一列中,那么它们之间布置有多少战舰。

作为一个资深的高级程序设计员,你被要求编写程序分析杨威利的指令,以及回答莱因哈特的询问。

最终的决战已经展开,银河的历史又翻过了一页输入文件galaxy.in的第一行有一个整数T(1=T=500,000),表示总共有T条指令。

以下有T行,每行有一条指令。

指令有两种格式:

1.Mij:

i和j是两个整数(1=i,j=30000),表示指令涉及的战舰编号。

该指令是莱因哈特窃听到的杨威利发布的舰队调动指令,并且保证第i号战舰与第j号战舰不在同一列。

2.Cij:

i和j是两个整数(1=i,j=30000),表示指令涉及的战舰编号。

该指令是莱因哈特发布的询问指令。

输出文件为galaxy.out。

你的程序应当依次对输入的每一条指令进行分析和处理:

如果是杨威利发布的舰队调动指令,则表示舰队排列发生了变化,你的程序要注意到这一点,但是不要输出任何信息;如果是莱因哈特发布的询问指令,你的程序要输出一行,仅包含一个整数,表示在同一列上,第i号战舰与第j号战舰之间布置的战舰数目。

如果第i号战舰与第j号战舰当前不在同一列上,则输出-1。

样例输入4M23C12M24C42样例输出-11这一题需要增加两个域,一个表示该元素所在集合中元素的总个数,用count表示;另一个是在该集合中,这个元素之前有多少个元素,用before表示。

初始的时候fatheri=i;counti=1;beforei=0;

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 英语

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1