不想看模板,想直接看题目的请戳下面目录:

目录:

HDU 1213 How Many Tables【传送门】

HDU 1232 畅通工程 【传送门】

POJ 2236 Wireless Network 【传送门】

POJ 1703 Find them, Catch them 【传送门】


先上模板:

  1. #define MAXN 根据编号需要
  2. int per[MAXN],rank[MAXN];
  3.  
  4. void init(int n)
  5. {
  6. int i;
  7. for(i=;i<=n;i++)
  8. {
  9. per[i]=i;rank[i]=
  10. }
  11.  
  12. }
  13.  
  14. int find(int x)
  15. {
  16. if(x==per[x])
  17. return x;
  18. return per[x]=find(per[x]);
  19. }
  20.  
  21. void unite(int x,int y)
  22. {
  23. x=find(x);
  24. y=find(y);
  25. if(x==y)
  26. return;
  27. if(rank[x]>rank[y])
  28. per[y]=x;
  29. else
  30. {
  31. per[x]=y;
  32. if(rank[x]==rank[y])
  33. rank[y]+=;
  34. }
  35. }
  36.  
  37. bool same(int x,int y)
  38. {
  39. return find(x)==find(y);
  40. }

并查集详解请访问:(通俗易懂解释)

https://blog.csdn.net/lesileqin/article/details/96703143


接下来来看几个例子:

HDU 1213 How Many Tables【传送门】

题目大意:有一个人过生日,请到了他的诸多朋友,但是这些朋友之间有的认识,有的不认识。这个人想尽可能的把相互之间认识的人凑到一张桌子上,不认识的人则去另一张桌子。朋友们互相认识的规则是:比如A认识B,B认识C,那么A,B,C就可以凑到一桌子上。现在问:他的朋友们以这样的规则能凑够几桌。

解题思路:运用并查集,把相互认识的人都联合一下,到最后计算数组中有几个per值等于自身的人就可以了。

  1. #include<iostream>
  2.  
  3. using namespace std;
  4.  
  5. int f[];
  6.  
  7. void init(int n)
  8. {
  9. for(int i=;i<=n;i++)
  10. f[i]=i;
  11. }
  12.  
  13. int find(int a)
  14. {
  15. while(a!=f[a])
  16. {
  17. a=f[a];
  18. }
  19. return a;
  20. }
  21.  
  22. void Combin(int a,int b)
  23. {
  24. int ta,tb;
  25. ta=find(a);
  26. tb=find(b);
  27.  
  28. if(ta!=tb)
  29. f[ta]=tb;
  30. }
  31.  
  32. int answer(int n)
  33. {
  34. int sum=;
  35. for(int i=;i<=n;i++)
  36. if(f[i]==i)
  37. sum++;
  38. return sum;
  39. }
  40.  
  41. int main()
  42. {
  43.  
  44. int t;
  45. cin >> t;
  46. while(t--)
  47. {
  48. int n,m;
  49. cin >> n >> m;
  50. init(n);
  51. int a,b;
  52. for(int i=;i<m;i++)
  53. cin >> a >> b,Combin(a,b);
  54. cout << answer(n) << endl ;
  55. }
  56.  
  57. return ;
  58. }

HDU 1232 畅通工程 【传送门】

此处略去题目大意……

解题思路:其实这个题目和上一个题异曲同工,就是变换了一下条件,我们假设村子是上题的朋友,那么路就是朋友们之间的关系,那么两堆朋友之间连线,其实只需要一次就可以了,同样,三堆朋友之间要想相互认识,只需要两个关系就可以了,所以我们很容易可以得出朋友们要想都认识,只需要把朋友堆数 - 1 就可以了。

代码只需要将上题的输出结果-1即可 ,不再贴出。


POJ 2236 Wireless Network 【传送门】

题目大意:一片废弃的地方,ACM协会正在进行救援,可是所有电脑的通信设施都被破坏了,被修复好的电脑的信号传输距离只有d米,现在给出所有电脑的坐标,然后给出指令S与O,S后跟两个数字代表两个电脑的编号,询问这两台电脑是否能通信,如果能则输出SUCCESS,否则输出FALL;O后跟一个编号,代表修好一定电脑。

解题思路:此题运用并查集,在修复好一台电脑之后遍历所有修好的电脑,如果两点间距离小于d米,则连通两个点;遇到S的时候只需要判断是否连通即可。

  1. #include<iostream>
  2. #include<cmath>
  3. using namespace std;
  4. #define MAXN 1005
  5.  
  6. //坐标
  7. struct pos{
  8. int x,y;
  9. int par_id; //父辈id
  10. int rank; //树的高度
  11. };
  12.  
  13. struct pos par[MAXN]; //记录父亲
  14. bool isok[MAXN]; //是否被修复成功
  15.  
  16. float Distance(struct pos a,struct pos b)
  17. {
  18. float dis=sqrt(fabs(a.x-b.x)*fabs(a.x-b.x)+fabs(a.y-b.y)*fabs(a.y-b.y));
  19. return dis;
  20. }
  21.  
  22. void init(int n)
  23. {
  24. for(int i=;i<=n;i++)
  25. {
  26. par[i].par_id=i;
  27. par[i].rank=;
  28. isok[i]=false;
  29. }
  30. }
  31.  
  32. //查树根
  33. int find(int x)
  34. {
  35. if(par[x].par_id==x)
  36. return x;
  37. else
  38. return par[x].par_id=find(par[x].par_id);
  39. }
  40.  
  41. //合并
  42. void unite(int x,int y)
  43. {
  44. x=find(x);
  45. y=find(y);
  46. if(x==y)
  47. return;
  48. if(par[x].rank<par[y].rank)
  49. par[x].par_id=y;
  50. else{
  51. par[y].par_id=x;
  52. if(par[x].rank==par[y].rank)
  53. par[x].rank++;
  54. }
  55. }
  56.  
  57. //判断x和y是不是同一个集合
  58. bool same(int x,int y)
  59. {
  60. return find(x)==find(y);
  61. }
  62.  
  63. int main()
  64. {
  65. int N,d;
  66. char c;
  67. cin >> N >> d;
  68. init(N);
  69. for(int i=;i<=N;i++)
  70. {
  71. int x,y;
  72. cin >> x >> y;
  73. par[i].x=x;
  74. par[i].y=y;
  75. }
  76.  
  77. while(cin >> c)
  78. {
  79. int p,q;
  80. if(c=='O')
  81. {
  82. cin >> p;
  83. isok[p]=true;
  84. for(int i=;i<=N;i++)
  85. {
  86. if(isok[i]==true&&i!=p)
  87. {
  88. struct pos a,b;
  89. a.x=par[i].x;
  90. a.y=par[i].y;
  91. a.par_id=par[i].par_id;
  92. b.x=par[p].x;
  93. b.y=par[p].y;
  94. b.par_id=par[p].par_id;
  95. if(Distance(a,b)<=d)
  96. {
  97. // cout << Distance(a,b) << endl;
  98. unite(p,i);
  99. }
  100.  
  101. }
  102. }
  103. }
  104. else if(c=='S')
  105. {
  106. cin >> p >> q;
  107. if(same(p,q))
  108. cout << "SUCCESS\n";
  109. else
  110. cout << "FAIL\n";
  111. }
  112. // for(int i=1;i<=N;i++)
  113. // cout << par[i].par_id << " ";
  114. // cout << endl;
  115. }
  116. return ;
  117. }

POJ 1703 Find them, Catch them 【传送门】

题目大意:有两个帮派,警察现在抓住了N个罪犯,输入字母A或D,后面跟着两个罪犯的编号。如果字符是A,则代表这一次询问:如果不是一个帮派,则输出“In different gangs.”;是一个帮派输出"In the same gang.";否则输出“Not sure yet.”。如果是字符D,那就代表着后面的两个编号不属于一个帮派!

解题思路:需要一个标记数组vis,用来标记两个罪犯(a,b)不属于同一个帮派,如果标记数组两个罪犯都为0则代表不确定是哪个帮派,并且让vis[a]=b,vis[b]=a;如果vis[a]==0&&vis[b]!=0,则让vis[b]=a,并且连通a,vis[b];如果vis[b]==0&&vis[a]!=0,则让vis[a]=b,并且连通b,vis[a];最后一种情况是a与b的标记数组都不为0,那么连2019-07-21通a,vis[b],连通b,vis[a]最后判断即可。

  1. //#include<iostream>
  2. //using namespace std;
  3. #include<stdio.h>
  4. #define MAXN 100010
  5.  
  6. int per[MAXN],rank[MAXN],vis[MAXN];
  7.  
  8. void init(int n)
  9. {
  10. int i;
  11. for(i=;i<=n;i++)
  12. {
  13. per[i]=i;rank[i]=;vis[i]=;
  14. }
  15.  
  16. }
  17.  
  18. int find(int x)
  19. {
  20. if(x==per[x])
  21. return x;
  22. return per[x]=find(per[x]);
  23. }
  24.  
  25. void unite(int x,int y)
  26. {
  27. x=find(x);
  28. y=find(y);
  29. if(x==y)
  30. return;
  31. if(rank[x]>rank[y])
  32. per[y]=x;
  33. else
  34. {
  35. per[x]=y;
  36. if(rank[x]==rank[y])
  37. rank[y]+=;
  38. }
  39. }
  40.  
  41. int Same(int x,int y)
  42. {
  43. if(find(x)==find(y))
  44. return ;
  45.  
  46. }
  47.  
  48. int main()
  49. {
  50. // ios::sync_with_stdio(false);
  51. int t;
  52. scanf("%d",&t);
  53. // cin >> t;
  54. while(t--)
  55. {
  56. int n,m;
  57. scanf("%d%d",&n,&m);
  58. // cin >> n >> m;
  59. init(n);
  60. while(m--)
  61. {
  62. int a,b;
  63. char c[];
  64. scanf("%s",c);
  65. //getchar();
  66. scanf("%d%d",&a,&b);
  67. //cin >> c >> a >> b;
  68. //联立
  69. //printf("%c\n",c);
  70. if(c[]=='D')
  71. {
  72. if(vis[a]==&&vis[b]==)
  73. {
  74. vis[a]=b;
  75. vis[b]=a;
  76. }
  77. else if(vis[a]==)
  78. {
  79. vis[a]=b;
  80. unite(a,vis[b]);
  81. }
  82. else if(vis[b]==)
  83. {
  84. vis[b]=a;
  85. unite(b,vis[a]);
  86. }
  87. else{
  88. unite(a,vis[b]);
  89. unite(b,vis[a]);
  90. }
  91. }
  92. else{
  93. if(Same(a,b))
  94. printf("In the same gang.\n");
  95. //cout << "In the same gang.\n";
  96. else if(Same(a,vis[b]))
  97. //cout << "In different gangs.\n";
  98. printf("In different gangs.\n");
  99. else
  100. printf("Not sure yet.\n");
  101. //cout << "Not sure yet.\n";
  102. }
  103. }
  104. }
  105.  
  106. return ;
  107. }

【并查集】模板 + 【HDU 1213、HDU 1232、POJ 2236、POJ 1703】例题详解的更多相关文章

  1. HDU 1213 How Many Tables(并查集模板)

    http://acm.hdu.edu.cn/showproblem.php?pid=1213 题意: 这个问题的一个重要规则是,如果我告诉你A知道B,B知道C,这意味着A,B,C知道对方,所以他们可以 ...

  2. 【2018寒假集训Day 8】【并查集】并查集模板

    Luogu并查集模板题 #include<cstdio> using namespace std; int z,x,y,n,m,father[10001]; int getfather(i ...

  3. POJ-图论-并查集模板

    POJ-图论-并查集模板 1.init:把每一个元素初始化为一个集合,初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变). void init() { for ...

  4. 【并查集模板】 【洛谷P2978】 【USACO10JAN】下午茶时间

    P2978 [USACO10JAN]下午茶时间Tea Time 题目描述 N (1 <= N <= 1000) cows, conveniently numbered 1..N all a ...

  5. 【并查集模板】并查集模板 luogu-3367

    题目描述 简单的并查集模板 输入描述 第一行包含两个整数N.M,表示共有N个元素和M个操作. 接下来M行,每行包含三个整数Zi.Xi.Yi 当Zi=1时,将Xi与Yi所在的集合合并 当Zi=2时,输出 ...

  6. Memcached集群/分布式/高可用 及 Magent缓存代理搭建过程 详解

    当网站访问量达到一定时,如何做Memcached集群,又如何高可用,是接下来要讨论的问题. 有这么一段文字来描述“Memcached集群” Memcached如何处理容错的? 不处理!:) 在memc ...

  7. Android查缺补漏(IPC篇)-- 款进程通讯之AIDL详解

    本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...

  8. Android查缺补漏(IPC篇)-- 进程间通讯之AIDL详解

    本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...

  9. HDU 1213 - How Many Tables - [并查集模板题]

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1213 Today is Ignatius' birthday. He invites a lot of ...

随机推荐

  1. Delphi中取得汉字的首字母(十分巧妙)

    function Tdm.GetHzPy(const AHzStr: string): string;const  ChinaCode: array[0..25, 0..1] of Integer = ...

  2. FMX中实现PostMessage的方法

    首先,做为一个从Windows下转过来的开发人员,许多时候,我们喜欢用PostMessage来触发一些异步执行的代码,但遗憾的是,FMX做为EMB的跨平台库的基础,只提供了SendMessage方法, ...

  3. PHP中关于时间、时区、本地时间、UTC时间、GMT时间、时间戳等知识的梳理

    在PHP开发中,我们经常会在时间问题上被搞糊涂,比如我们希望显示一个北京时间,但是当我们使用date函数进行输出时,却发现少了8个小时.几乎所有的php猿类都必须对php中几个重要的时间转换等方法进行 ...

  4. Mac上使用brew安装nvm来支持多版本的Nodejs

    brew方式 如果机器没有安装过node,那么首先brew install nvm安装nvm. 其次需要在shell的配置文件(~/.bashrc, ~/.profile, or ~/.zshrc)中 ...

  5. Netty源码分析--创建Channel(三)

    恩~,没错,其实这一篇才是真正的开始分析源码,你打我呀~. 先看一下我Netty的启动类 private void start() throws Exception { EventLoopGroup ...

  6. Django高级编程之自定义Field实现多语言

    自定义数据库字段 扩展默认的models.CharField和models.TextField使之成为支持多语言的字段. 可以轻松实现复用,无需配置多余选项 from django.conf impo ...

  7. 使用wireshark捕获SSL/TLS包并分析

    原创博客,转载请注出处! TLS运作方式如下图:

  8. Scala 学习之路(六)—— 常用集合类型之 List & Set

    一.List字面量 List是Scala中非常重要的一个数据结构,其与Array(数组)非常类似,但是List是不可变的,和Java中的List一样,其底层实现是链表. scala> val l ...

  9. 【Linux杂记】Linux配置静态IP地址,修改主机名、host

    博主使用的系统是:乌班图16.04 1.设置静态IP方法如下: #sudo vim /etc/network/interfaces #修改如下部分: auto eth0//ipconfig命令查看网卡 ...

  10. .NET Core IdentityServer4实战 第六章-Consent授权页

    在identityServer4中登陆页面只要是成功了,就会注册一个Cookie在服务器资源上,像现在大部分的网站第三方授权,都是经过一个页面,然后选需要的功能,IdentityServer4也给我们 ...