题目大意:输入两个整数n,m(n表示点的个数,m表示操作数)。在接下来的m行中,对点的操作有两种

1)M a b 。 表示将a、b并到一个集合中

2)S a .表示将a从原来的集合中去除,而成为一个单独的集合

解题思路:并查集

1)

解题思路:并查集,M代表合并,S代表删除,下面讲一下删除操作

大家都知道合并操作就是找到找到两个节点的父亲,修改父亲,如果删除就是将该点的父亲重新设置成自己,这样行不行呢?

这是不行的,比如1,2,3的父亲都是1,现在删除1,1的父亲还是1,2,3也是1,集合还是1个,正确的应该是2个。

那删除节点的父亲不设成自己给新申请一个节点当做父亲,比如1,2,3的父亲都是1,在一个集合,现在删除1,申请了4当做1的父亲,2,3父亲都是1,然后Find(2)找2的父亲

2的父亲是1,但是1的父亲是4,所以给2的父亲更新成了4,3同理,所以还不行。

正确的方法是每一个点都设立一个虚拟父亲比如1,2,3的父亲分别是4,5,6,现在合并1,2,3都在一个集合,那他们的父亲都是4,现在删除1,那就给1重新申请一个节点7

现在2,3的父亲是4,1的父亲是7,删除成功。

2)定义数组  int[] father

int[] rank  
   father[i]=i,则i表示本集合且i是集合对应的树的根 
   father[i]=j,则表示j是i的父节点 
   rank[i]代表集合i的秩(比如子孙的多少或树的高度等),用于合并集合,秩小的合并到秩大的。

3)

开始让我混淆的一个地方是,假设如下情况
M 0 2
M 1 2
S  2
那么按照并查集来做, 0指向2, 1指向2,即
0 -->2
1 -->2 ,
那么删除2之后,我以为题目意思是所有与2有关系的都要删除, 那么这两个关系都要去掉, 又变成独立的3个了。
但是我这种理解是错的。 合并起来后就是一个集合{0,1,2},  如果把2删除掉之后, {0,1}还是集合。

理解题意之后, 我们知道用并查集来构造集合是很容易的,但是要把集合中的一个删掉,却很不容易。 通过这题,我学习到了所谓的设立需父节点的方法。
关键的过程是假设要删除x点, 那么不是真的删除x点, 而是通过一个映射(这里用数组majia[N]),把x变成一个新的点即majia[x] = newNode.那么, 原来的那些集合还是不变,只是少了个x点。

-----------------------------------------------------------------------------------------------------

以下代码是根据解题思路1)写出来的。

代码如下:

  1. /*
  2. * 2473_4.cpp
  3. *
  4. * Created on: 2013年8月23日
  5. * Author: Administrator
  6. */
  7.  
  8. #include <iostream>
  9.  
  10. using namespace std;
  11.  
  12. int father[1100000];
  13. bool flag[1000050];
  14. int id;
  15.  
  16. int find(int x){
  17. int r,i,j;
  18.  
  19. r = x;
  20. while( r!= father[r]){
  21. r = father[r];
  22. }
  23.  
  24. i = x;
  25. while(i!=r){
  26. j = father[i];
  27. father[i] = r;
  28. i = j;
  29. }
  30.  
  31. return r;
  32. }
  33.  
  34. /**find(int a) 也可以写成以下形式:
  35. int find(int a){
  36. if(a != father[a]){
  37. father[a] = find(father[a]);
  38. }
  39.  
  40. return father[a];
  41. }
  42. */
  43. void join(int x , int y){
  44. int fx = find(x);
  45. int fy = find(y);
  46.  
  47. if(fx != fy){
  48. father[fx] = fy;
  49. }
  50. }
  51.  
  52. void make_set(int n , int m){
  53. int i;
  54. for(i = 0 ; i < n ; ++i){
  55. father[i] = i + n;
  56. }
  57.  
  58. for(i = n ; i <= n + n + m ; ++i){
  59. father[i] = i;
  60. }
  61. }
  62.  
  63. void delete_set(int x){
  64. father[x] = id++;
  65. }
  66.  
  67. int main(){
  68. int n,m,count = 1;
  69. while(scanf("%d%d",&n,&m)!=EOF,n||m){
  70. int i;
  71. id = n + n;
  72. make_set(n,m);//****千万别漏了
  73. for( i = 0 ; i < m ; ++i){
  74. int a,b;
  75. char c[5];
  76. scanf("%s",c);
  77. if(c[0] == 'M'){
  78. scanf("%d%d",&a,&b);
  79. join(a,b);
  80. }else if(c[0] == 'S'){
  81. scanf("%d",&a);
  82. delete_set(a);
  83. }
  84. }
  85.  
  86. memset(flag,0,sizeof(flag));
  87. int ans = 0;
  88. for( i = 0 ; i < n ; ++i){
  89. int x = find(i);
  90. if(!flag[x]){
  91. ans++;
  92. flag[x] = true;
  93. }
  94. }
  95.  
  96. printf("Case #%d: %d\n",count++,ans);
  97.  
  98. }
  99. }

(step5.1.2)hdu 2473(Junk-Mail Filter——并查集)的更多相关文章

  1. (step5.1.6)hdu 1272(小希的迷宫——并查集)

    题目大意:输入一系列的点,判断这些点组成的图符不符合小希的思路(无环.连通) 解题思路: 1)如果两个节点的根节点相同,那么在这两个节点之间添加1条边以后,这个图肯定有环路. 2)孤立节点:被使用过& ...

  2. hdu 2473 Junk-Mail Filter (并查集之点的删除)

    Junk-Mail Filter Time Limit: 15000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  3. HDU 2473 Junk-Mail Filter 并查集,虚拟删除操作

    http://acm.hdu.edu.cn/showproblem.php?pid=2473 给定两种操作 第一种是合并X Y 第二种是把X分离出来,就是从原来的集合中分离出来,其它的关系不变. 关键 ...

  4. HDU 2473 Junk-Mail Filter(并查集的删除操作)

    题目地址:pid=2473">HDU 2473 这题曾经碰到过,没做出来. .如今又做了做,还是没做出来. ... 这题涉及到并查集的删除操作.想到了设一个虚节点,可是我把虚节点设为了 ...

  5. HDU 2473 Junk-Mail Filter 并查集删除(FZU 2155盟国)

    http://acm.hdu.edu.cn/showproblem.php?pid=2473 http://acm.fzu.edu.cn/problem.php?pid=2155 题目大意: 编号0~ ...

  6. hdu2473 Junk-Mail Filter 并查集+删除节点+路径压缩

    Description Recognizing junk mails is a tough task. The method used here consists of two steps:  1) ...

  7. HDU HDU1558 Segment set(并查集+判断线段相交)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1558 解题报告:首先如果两条线段有交点的话,这两条线段在一个集合内,如果a跟b在一个集合内,b跟c在一 ...

  8. hdu 1257 小希的迷宫 并查集

    小希的迷宫 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=1272 D ...

  9. hdu 3635 Dragon Balls(并查集应用)

    Problem Description Five hundred years later, the number of dragon balls will increase unexpectedly, ...

  10. <hdu - 1272> 小希的迷宫 并查集问题 (注意特殊情况)

     本题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1272 Problem Description: 上次Gardon的迷宫城堡小希玩了很久(见Probl ...

随机推荐

  1. Demo_CS(移动,切换枪支,发射子弹)

    using UnityEngine; using System.Collections; public class Gun : MonoBehaviour { private Animator ani ...

  2. [置顶] C语言单元测试框架

    unitest.h /****************************************************************************** * * * This ...

  3. C++ 求阶乘 四种方法

    来总结下求阶乘的各种方法哈. 写在最前:①各个代码仅仅是提供了求阶乘的思路,以便在实际须要时再来编码,代码并不健壮!②各个程序都在1到10内測试正确. 代码一: #include<iostrea ...

  4. session绑定javaBean

    1.HttpSessionBindingListener   这个监听器,可以让javaBean对象,感知它被绑定到session中或从session中移除.2.HttpSessionActivati ...

  5. josn 转php

    $data = josn_decode(data,[true]); 加true转化为php数组:不加为对象,使用:$data->'字段'.

  6. Retrofit2 简介 语法 案例

    简介 官网:http://square.github.io/retrofit/ GitHub:https://github.com/square/retrofit/ compile 'com.squa ...

  7. (转)java之多线程

    Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程 ...

  8. ASP.NET-FineUI开发实践-13(一)

    开原版好像是没有gird树,有一个扩展列下的模拟树列,就是不能展开,专业版有,开原版我弄了弄,思路是有,就是不是很好实现.这篇博客直接写出了(一)说明一个肯定是写不完的. FineUI重在封装,改这个 ...

  9. 经验分享:CSS浮动(float,clear)通俗讲解(转载)

    很早以前就接触过CSS,但对于浮动始终非常迷惑,可能是自身理解能力差,也可能是没能遇到一篇通俗的教程. 前些天小菜终于搞懂了浮动的基本原理,迫不及待的分享给大家. 写在前面的话: 由于CSS内容比较多 ...

  10. 依赖注入与Unity(一) 介绍

        在你学习依赖注入和Unity之前,你需要明白你为什么要使用它们.为了明白为什么要使用它们,你应该明白依赖注入和Unity能够帮助你解决什么类型的问题.作为介绍部分,这一章不会涉及太多关于Uni ...