stl 和并查集应用

Posted detrol

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了stl 和并查集应用相关的知识,希望对你有一定的参考价值。

抱歉这么久才写出一篇文章,最近进度有点慢。这么慢是有原因的,我在想如何改进能让大家看系列文章的时候更方便一些,现在这个问题有了答案,在以后的推送中,我将尽量把例题和相关知识点在同一天推出,其次在代码分享方面,我也做了改进,对应当加入注释的地方略微加了注释。

 

 


 

先介绍一下今天分享的题目

技术分享

 

题目简述:有 n 个人,其中存在很多对朋友关系(不排除有的人没有朋友),这种朋友关系满足对称、传递性质(是否是自反关系对这道题没有影响),即 如果A 和 B 是朋友,就有 B 和 A 是朋友; 如果 A 和 B 是朋友且 B 和 C 是朋友,就有 A 和 C 也是朋友关系。简言之:满足朋友关系的人要么有直接的朋友关系,要么两人有共同的朋友。

由上述特性可以在一个群体间建立起很多个关系网络。

 

分析一下建立的朋友关系网络具备的特征。对称性说明该关系是无向关系,此外该网络还满足传递性,举个例子:如果其中一个关系网络中有 1 、2、 3、 4  这四个人,

已知

1  < - > 2

2  < - > 3 

1  < - > 4

由  1  < - > 2 与 2  < - > 3  可以得出 1 < - > 3

由  1  < - > 2 与 1  < - > 4  可以得出 2 < - > 4

由  2  < - > 3 与 2  < - > 4  可以得出 3 < - > 4

 

总结:

编号 1 的朋友为:2 、3 、4

编号 2 的朋友为:1 、3 、4

编号 3 的朋友为:1 、2 、4

编号 4 的朋友为:1 、2 、3

 

由此可以得出结论,这个网络中任意两个人都必须满足朋友关系,且一个人一旦能与该网络某一个人发生关系,此人同样与其他所有人都有关系。如果一个人有朋友,那么这些互为朋友的人必然能够形成一个封闭的关系网络,这就形成了两个极端:要么孤身一人没有朋友,要么就必须和所在关系网络中所有人成为朋友。用图论的知识解释:根据朋友关系的对称性可以得出这个题目中形成的图是无向图,形成的关系网络要么是平凡图(只有一个孤立点),要么是完全图(任意两点之间均连通)。

 


 

题目要求:第一行给出总人数 n 和 总关系对数 m,将 n 个人从 1 到 n 进行编号,并给出满足朋友关系的 m 对编号,试判断给出的 m 对关系是否构成了满足题目所述朋友关系的网络体系。是输出 YES ,否则输出 NO 。

 

输入输出数据要求如下:

技术分享

 

m 和 n 均不超过 150 000 。

 

测试样例如下:

技术分享

 


 

在对题目梗概了解之后,不妨先来观察一下测试样例。

以第一组测试样例为例进行分析:

n = 4 ,m = 3 ,由 3 对朋友关系可以建成如下关系网络体系:

技术分享

由上图可以看出 左半部分满足完全图,右半部分满足平凡图,该体系满足题目所要求的朋友关系,因此输出答案 YES 。

 

再来看第二组测试数据:

n = 4 ,m = 4 ,由所给四对关系可以建成如下关系网络体系:

技术分享

由上图可以看出,4 与 2 、1均未直接连接,因此不满足完全图条件,答案为 NO 。

 


 

在对上面两个样例进行分析后发现,判断一个关系网络体系是否满足条件,只需要对每一个连通分量进行判断,如果其中存在一个既不是完全图也不是平凡图的分量,那么这个体系就不满足条件。

人眼去观察的时候,可能一眼就能看出一个连通分量甚至一个关系网络体系是不是满足条件,但是计算机怎么判断呢?计算机判断的时候,必须有一个固定模式形成的标准,用这个标准和形成的实例进行对比,完全匹配的是正确的,不完全匹配则是错误的。这个过程分为以下两步:

 

第一步:应该建立起输入信息所给的关系网络体系,并将其储存。建立关系网络体系分为两个方面,第一个方面,由于题目要求判断给定的关系是否满足条件,因此要将原来给定的 m 对关系存储,第二个方面,由于朋友关系本身具备的特征,要将对称性和传递性的关系体现出来,也就意味着,在输入的过程中,需要对图进行完善,将对称性和传递性所产生的关系填充。因此,该题目必须建立两个独立的结构,一个单纯存储题目给定的关系,另一个则用来存储经过修正的关系网络体系。

第二步:将原关系和修正关系进行对比。

 


 

理论知识介绍完毕,下面是具体的实现方案:

和以往一样,介绍普通思路和修改思路两种方案

 

方案一

  1. 原关系的存储

    原来的关系给的是 m 对朋友的编号(不重复),由于要满足对称性关系,因此应该存储双向关系,回忆一下,最直观的存储图的结构是--邻接矩阵,说得直白一点就是二维数组,这种结构存储图的好处是,查找任意两个元素之间的关系,时间复杂度是 o(1),但这种结构缺点比较致命,空间利用率不高且对整个图进行遍历时,时间消耗太多。本题m、 n 的范围给的是150 000,开二维数组来实现肯定不现实(我不会告诉你我尝试的时候程序崩溃到连数字都无法读入);另外还有一种方法用来存储图结构--邻接表,这种结构空间利用率是比较高的,但是,链表的实现编写起来比较麻烦,稍有不慎,就会有指针越界的错误出现。不过在对链表操作熟悉的前提下,也不失为一种可行方案。

  2. 修正关系的存储

    修正关系要满足对称性和传递性,根据题目所给的要求,相互之间存在朋友关系的人,放在同一个集合中即可。为什么仅仅存入同一个集合就可以呢?因为本题中任一关系网络均为无向完全图,也就是每个关系网络中的任何一个个体都与同一关系网络内其余所有个体相联系,所有成员不存在特殊需要标记的特性。如果仅仅需要将所有成员分成若干个集合,那么用并查集来实现这一步骤是再合适不过了。

    并查集实现的功能:按照某种特定的关系,将所有元素划分为若干集合,并在每个集合中选出一个代表元素(俗称father)来代表该集合,这种行为类似于在学校这样的大环境中分了若干个班级,每个班级选出一个班长,由班长作为班级的代表和外界进行沟通交流。

  3. 原关系和修正关系的对比

       由于修正关系是按照正确的关系建立的关系网络,因此需要判断的是原关系是否有不同于修正关系的地方,即对于修正关系中出现的每一对关系,原关系图中是否存储了该关系。按照这种思路每在修正关系网络中找到一对关系,就需要在存储原关系的邻接矩阵(或邻接表)中查找该关系是否存在。这种思路的时间复杂度远远超过 o(n*n),在150 000 这样规模的数据上是不可取的。

 

原关系和修正关系的存储结构比较好改进,但是关系对比这个方向怎么改进?既然遍历会超时,能不能换个思路进行改进呢?现在重新捋一下思路,完全图有很多性质,我们能不能利用它的某些性质避开对整个图的遍历呢?对于一个 n 个节点的完全图,其中的每一个节点必然与其余节点相连接,也就意味着与之相关联的关系个数为 n-1,那么只需要确定每个关系网络中所含的节点的个数 n ,再对原图进行遍历,判断每个节点是否与所在关系网络满足上述关系即可。

现在问题转化成了两个简单的问题:

一、求修正关系网络体系中连通分支的个数以及对应的节点数。

二、求解原关系网络体系中与每个节点相关的关系个数并与修正关系中对应的个数进行对比。

准备好所有需要用的数据,只需要一次遍历,时间复杂度为 o(n)就可完成。这就产生了如下方案。

方案二

 

  1. 原关系的存储

    利用 STL 中的 vector 容器,实现对原关系网络体系的动态存储,开 1e6 的 vector 数组 g[1e6],将与编号 i 相关的所有个体存入 g[i]分量中。这个时候,直接调用 g [i]. size()函数,就可求出与 i 有关的关系个数。(需要注意的一点就是,在此建立的关系是双向的)

  2. 修正关系的存储

    对于修正关系网络体系,可以使用并查集思想对 father 数组进行修正,由于在原关系和修正关系的对比过程中,用到的只有连通分支的代表和节点总数的对应关系,因此,可以利用STL 中的 map 容器,将两者的映射关系存入即可。

  3. 原图和修正图的对比

    逐个比较编号 i 的 分量的关系数 g [i]. size()和 map 中 存储的 i 所在关系网络    的节点数 map[ find( i )]是否满足  

    map[ find( i )]-1 = g[i] . size()

     

 

这就实现了 建图而避开对图遍历 的目的。

 


 

以上是理论介绍,有需要查看代码的朋友打开网页http://paste.ubuntu.com/24324517/。

以上是关于stl 和并查集应用的主要内容,如果未能解决你的问题,请参考以下文章

并查集

CF553C Love Triangles(带权并查集)

可持久化并查集

[HDOJ2818]Building Block(带权并查集,路径压缩)

CodeForces - 1209D Cow and Snacks 并查集

[POJ1236]Network of Schools(并查集+floyd,伪强连通分量)