`
BlogDown
  • 浏览: 214226 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

可供快速查:并查集

 
阅读更多

最近学习了并查集、线段树、树状数组以及RMQ(Range Minimum Query)这几种关于快速查找
的数据结构和算法,并做了一些ACM的题目巩固了一下。准备写一下总结。
本次总结一下并查集:
并查集对解决不相交集合的合并查找操作非常有效,主要提供了一下几个方法:
make_set(x) 把每一个元素初始化为一个集合
find_set(x) 查找一个元素所在的集合
union_set(x,y) 合并x,y所在的两个集合
空间复杂度为O(N),建立一个集合的时间复杂度为O(1),N次合并M查找的时间复杂度为O(M Alpha(N)),
这里Alpha是Ackerman函数的某个反函数,在很大的范围内这个函数的值可以看成是不大于4的,所以并
查集的操作可以看作是线性的。
并查集针对不同的问题有两种不同的实现:
第一种:
make_set(x)的时候parent[x] = x,也就是根的parent指向自己,以此来判断这个元素是否为根元素,
rank值记录树的高度,合并的时候尽量让小的合并到大的集合上,这样可以减少数的高度。
代码如下:

int parent[50001];
int rank[50001];

void make_set(int x){
parent[x] = x;
rank[x] = 0;
}

//查找的时候,进行路径压缩parent[x] = find_set(parent[x]),
//把查找路径上的结点都指向跟结点,减小树的高度
int find_set(int x){
if(x != parent[x]) parent[x] = find_set(parent[x]);
return parent[x];
}

void union_set(int x,int y){
int r1 = find_set(x);
int r2 = find_set(y);
if(r1 == r2) return;//如果两个元素在相同的集合中,直接retun;

if(rank[r1] < rank[r2]//把rank值较小的集合合并到达的集合中
parent[r2] = r1;
else{
if(rank[r1] == rank[r2])//两个rank值相等的树合并后rank要增加一
rank[r2] += 1;
parent[r1] = r2;
}
}

第二种:
make_set的时候把parent[x] = -1,根节点parent记录了该集合元素个数
的相反数,所以这种方法很适合想知道某个元素所在的集合的个数的情况。
int parent[30001];

void make_set(int x){
parent[x] = -1;
}

int find_set(int x){
int p = x;
while(parent[p] > 0) p = parent[p];//找到跟结点
while(x != p){//查找并压缩路径,让查找路径上的每一个x的parent[x] = p,p为根节点
int temp = parent[x];
parent[x] = p;
x = temp;
}
return x;
}

void union_set(int x,int y){
int r1 = find_set(x);
int r2 = find_set(y);

if(r1 == r2) return;
if(parent[r1] < parent[r2]){//集合小的合并到集合大的上,并更新集合元素个数的计数
parent[r1] += parent[r2];
parent[r2] = r1;
}else{
parent[r2] += parent[r1];
parent[r1] = r2;
}
}
以下是这两种并查集的两道ACM应用,可以巩固一下学习的知识:
poj2524 http://acm.pku.edu.cn/JudgeOnline/problem?id=2524
这道题目的主要意思是:n个大学生,指出m对宗教信仰相同的学生,然后让你估算这n个学生中最多
有多少种宗教信仰。
这道题很简单,把宗教数初始化为学生数n,对给出的每对大学生i,j,如果他们在不同的集合,那么
就合并,然后宗教的数量减一
以下是AC的代码:

#include<iostream>
using namespace std;

int parent[50001];
int rank[50001];

void make_set(int x){
parent[x] = x;
rank[x] = 0;
}

int find_set(int x){
if(x != parent[x]) parent[x] = find_set(parent[x]);
return parent[x];
}

void union_set(int x,int y){
int r1 = find_set(x);
int r2 = find_set(y);
if(r1 == r2) return;

if(rank[r1] < rank[r2])
parent[r2] = r1;
else{
if(rank[r1] == rank[r2])
rank[r2] += 1;
parent[r1] = r2;
}
}

int main(){
int m,n;
int ncases = 0;
int i = 0;
while(cin >> n >> m, n){
int a,b;
++ncases;
for(i = 0; i < n; i++){
make_set(i);
}

for(i = 0; i < m; i++){
cin >> a >> b;
int x = find_set(a);
int y = find_set(b);
if(x != y){//不同的集合,合并并减一
n--;
union_set(x,y);
}
}
cout << "Case " << ncases << ": " << n << endl;
}
return 0;
}

poj 1611 The Suspects http://acm.pku.edu.cn/JudgeOnline/problem?id=1611
这道题的意思是有一种传染病SARS,学生有很多的groups,如果groups的一个学生是疑似患者Suspect,
则整个组的其他人都是Suspects,但一个人可能属于不同的组,初始0是suspect,问学生中有多少个
Suspects.
这个题目很简单,把同一组的人进行合并,然后查找一个0元素所在集合元素的个数,由于要统计一个
集合元素的个数,所以使用第二种构造并查集的方法。
AC的代码:

Cpp代码 复制代码
  1. #include<iostream>
  2. usingnamespacestd;
  3. intparent[30001];
  4. voidmake_set(intx){
  5. parent[x]=-1;
  6. }
  7. intfind_set(intx){
  8. intp=x;
  9. while(parent[p]>0)p=parent[p];
  10. while(x!=p){
  11. inttemp=parent[x];
  12. parent[x]=p;
  13. x=temp;
  14. }
  15. returnx;
  16. }
  17. voidunion_set(intx,inty){
  18. intr1=find_set(x);
  19. intr2=find_set(y);
  20. if(r1==r2)return;
  21. if(parent[r1]<parent[r2]){
  22. parent[r1]+=parent[r2];
  23. parent[r2]=r1;
  24. }else{
  25. parent[r2]+=parent[r1];
  26. parent[r1]=r2;
  27. }
  28. }
  29. intmain(){
  30. intn,m,i=0;
  31. while(cin>>n>>m,n){
  32. for(i=0;i<n;i++){
  33. make_set(i);
  34. }
  35. for(i=0;i<m;i++){
  36. intk;
  37. cin>>k;
  38. intfirst_s,s;
  39. cin>>first_s;
  40. for(intj=1;j<k;j++){
  41. cin>>s;
  42. union_set(first_s,s);
  43. }
  44. }
  45. cout<<-parent[find_set(0)]<<endl;
  46. }
  47. return0;
  48. }


其他来自fandy_wang总结中提供的一些相关题目:
POJ 1182 食物链
并查集的拓展注意: 只有一组数据;
要充分利用题意所给条件:有三类动物A,B,C,这三类动物的食物链
构成了有趣的环形。A吃B, B吃C,C吃A。也就是说:只有三个group
POJ 2492 A Bug's Life 并查集的拓展
法一:深度优先遍历
每次遍历记录下该点是男还是女,只有:男-〉女,女-〉男满足,否则,找到同性恋,结束程序。
法二:二分图匹配
法三:并查集的拓展:和1182很像,只不过这里就有两组,而1182是三组,1611无限制
POJ 1861 Network == zju_1542 并查集+自定义排序+贪心求"最小生成树"
答案不唯一,不过在ZOJ上用QSORT()和SORT()都能过,在POJ上只有SORT()才能过...
POJ 1703 Find them, Catch them 并查集的拓展
这个和POJ 2492 A Bug's Life很像,就是把代码稍微修改了一下就AC了!
注意:And of course, at least one of them belongs to Gang Dragon, and the same for Gang Snake. 就是说只有两个组。
POJ 2236 Wireless Network 并查集的应用
需要注意的地方:1、并查集;2、N的范围,可以等于1001;3、从N+1行开始,第一个输入的可以是字符串。
POJ 1988 Cube Stacking 并查集很好的应用
1、与 银河英雄传说==NOI2002 Galaxy一样;2、增加了一个数组behind[x],记录战舰x在列中的相对位置;3、详细解题报告见银河英雄传说。
JOJ 1905 Freckles == POJ 2560 最小生成树
法一:Prim算法;法二:并查集实现Kruskar算法求最小生成树
JOJ 1966 Super Market III == PKU 1456 Supermarket 带限制的作业排序问题(贪心+并查集)
提高题目:
POJ 2912 Rochambeau
POJ 1733 Parity game
POJ 1308 Is It A Tree?

分享到:
评论

相关推荐

    神通数据库-数据库快速入门.pdf

    供的过程语言是 plOSCAR。在使用 plOSCAR 程序时,可用两种方法存储和执行程序。可以在本地存储程 序,并创建向数据库发送命令并处理结果的应用程序;也可以将程序在数据库中存储为存储过程,并创建执 行存储过程并...

    Oracle9i的init.ora参数中文说明

    并确保在同一事务处理种对相同数据的两次查询看到的是相同的值。 值范围: TRUE | FALSE 默认值: FALSE row_locking: 说明: 指定在表已更新或正在更新时是否获取行锁。如果设置为 ALWAYS, 只有在表被更新后才获取...

    中顶酒店客房管理系统 v8.1.2.zip

    12.简单直观的房台预定管理,方便快速预订并快速查询房台预订情况,客人来电自动弹屏,并可快速的为客户预订指定时间可供预订的房间 13.协议单位管理:强大的协议单管理管理功能,可对不同的协议单位设不同的房价...

    无需重启即可在 Mac 上运行 Windows 的应用程序.rar

    是一款专业的 Mac 虚拟机,可在 Windows 与 Mac OS 应用程序之间随意拖放文件并直接从 Mac dock 启动 Windows 程序,能够在 Mac 上以最便捷、快速、高效的方式运行 Windows! 是功能强大灵活度高的虚拟化方案,无论...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part4

    8.3.5 可滚动和可更新的结果集 296 8.4 jdbc数据源和连接池 299 8.5 mysql对中文的处理 302 8.6 小结 302 第9章 会话跟踪 303 9.1 用于会话跟踪的技术 303 9.1.1 ssl会话 304 9.1.2 cookies 304 9.1.3 url...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part3

    8.3.5 可滚动和可更新的结果集 296 8.4 jdbc数据源和连接池 299 8.5 mysql对中文的处理 302 8.6 小结 302 第9章 会话跟踪 303 9.1 用于会话跟踪的技术 303 9.1.1 ssl会话 304 9.1.2 cookies 304 9.1.3 url...

    eas供应链dep案例集

    单据操作控制修改 EASSCMA1P0070 仓库仓管员可跨组织选择 目前客户在选择仓管员时只能选择当前组织或平级组织,不能选择上级组织的职员,这样造成管理上的非常不便,因为在很多情况下仓管员并不是一定是当前组织的。...

    Android SQLite--小巧好用的SQLite GUI管理工具

    SQLiteSpy是一个快速和紧凑的图形用户界面的SQLite数据库管理软件。它可以读取sqlite3文件并执行SQL。图形用户界面使得它很容易分析和操纵sqlite3的数据库。 注意:SQLiteSpy是免费供个人和教育用途,SQLiteSpy主要...

    URULE是一款基于RETE算法的纯Java规则引擎.zip

    提供规则集、决策表、决策树、评分卡,规则流等各种规则表现工具及基于网页的可视化设计器,可快速开发出各种复杂业务规则。 开发工具在软件开发生命周期中扮演着至关重要的角色,它们旨在简化和加速从概念设计到...

    生产线设计方案.docx

    在线 复改进了SQL服务器的可用性,因为只有正在被恢复的数据是无法使用的,而数据库的其他部分依然在线、可供使用。 ·在线检索操作:在线检索选项可以在指数数据定义语言 (DDL)执行期间,允许对基底表格、或集簇...

    酒店管理信息系统课程设计.doc

    目前,教材管理信息系统已得到了大量应用,有许多可供参考的成功系统。从 技术角度考虑,此信息系统开发可行。 2.2.2经济可行性 目标系统开发需求比较低,加上具有成熟的软硬件环境,所以在软硬件的支出上十分 有限...

    大数据场景化解决方案.pdf

    ⼤数据的概念 维基百科的定义: ⼤数据是指利⽤常⽤软件⼯具捕获、管理和处理数据所耗时间超过可容忍时间的数据集。 2.⼤数据主流技术 数据采集: 使⽤Flume,可进⾏流式⽇志数据的收集。 使⽤Sqoop可以交互关系型...

    安卓Android平台的滴滴购物系统设计可导入Studio+源代码+文档说明+数据库.zip

    服务器和客户端数据通信格式: XML格式(用于传输查询的记录集)和json格式(用于传输单个的对象信息) 类似滴滴打车模式,通过消费者与商家的地址位置信息,快速有效地解决用户的购买需求,快捷有效地处理用户的购买...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part2

    8.3.5 可滚动和可更新的结果集 296 8.4 jdbc数据源和连接池 299 8.5 mysql对中文的处理 302 8.6 小结 302 第9章 会话跟踪 303 9.1 用于会话跟踪的技术 303 9.1.1 ssl会话 304 9.1.2 cookies 304 9.1.3 url...

    JAVA WEB 开发详解:XML+XSLT+SERVLET+JSP 深入剖析与实例应用.part5

    8.3.5 可滚动和可更新的结果集 296 8.4 jdbc数据源和连接池 299 8.5 mysql对中文的处理 302 8.6 小结 302 第9章 会话跟踪 303 9.1 用于会话跟踪的技术 303 9.1.1 ssl会话 304 9.1.2 cookies 304 9.1.3 url...

    网管教程 从入门到精通软件篇.txt

    Chkdsk 命令还可列出并纠正磁盘上的错误。  含有下列参数的 chkdsk 命令仅在使用故障恢复控制台时才可用。可在命令提示符下使用带有不同参数的 chkdsk 命令。  vol [drive:] [ chkdsk [drive:] [/p] [/r]  ...

    智点门窗工厂软件

    集订单、生产、销售、货运、账务、工人计件工资等于一体,包含套线自动计算,洞口净尺寸计算,生产单打印,包装标签打印,扫码计件,计件工资计算,移动下单,微信查进度等功能,从订单到发货业务流程可自定义,为...

    LJParser文本搜索与挖掘开发平台

    开发平台由多个中间件组成,各个中间件API可以无缝地融合到客户的各类复杂应用系统之中,可兼容Windows,Linux, Android,Maemo5, FreeBSD等不同操作系统平台,可以供Java,C,C#等各类开发语言使用。 LJParser是...

    毕设高分新项目-基于知识图谱的医生推荐系统python实现源码(含超详细项目说明+数据).zip

    通过事先考察,我们发现在进行疾病诊断的过程中,不仅仅是以身体的症状为依据,也有许多其他的所属关系可供我们参考。因此在进行关系抽取中,我们将各个实体间的关系分为8类,分别为属于、疾病常用药品、疾病对应...

Global site tag (gtag.js) - Google Analytics