• hdu 2473 Junk-Mail Filter


    https://vjudge.net/problem/HDU-2473

    题意:

    有一堆垃圾邮件需要识别。一开始每封邮件是互相不关联的。给出两种操作,第一种是指出两封邮件具有相同的特征,即两封邮件关联,且这种关系是传递的。第二种是指出某封邮件被误判,要求它断绝与其他所有邮件的关系,最后问一共有多少种互相不关联的邮件。

    思路:

    这种题一开始就看出来要用并查集,但是涉及到了删除操作,就比较困难,解决并查集单个节点的操作,有一种方法,叫做设立虚父马甲,这是从这题学到的。

    首先,看第一种方法,直接把孤立的节点设为自己。例如,有5封邮件,2,3,4,5的根均为1,当1被孤立的时候,par[1] = 1。2,3,4,5向上查询,查到的根还是为1,这种方法不可行。

    再来看第二种方法,把孤立的节点的父亲随便设置为一个不存在的值。例如1,2,3,4,5的根均为4,那么当4被孤立的时候,设置par[4] = 7,然后其他点向上查询,则都是查到的7,还是没有达到孤立的效果,这个方法也是不可行的。

    接下来看看设置虚父马甲的方法。这个方法是在初始化的时候把每一个节点i的父亲par[i]  设置为 i+n,然后把2 * n 到 2 * n + m的父亲设置为自己,为什么是2 * n + m呢?因为一共有m种操作,如果所有的操作都是孤立,那么就可能用到m个额外的虚父节点。举一个例子,有0,1,2,3,4,5一共6封信,每封信的初始化后父亲分别是6,7,8,9,10,11,现在假设是以2为根,那么实际情况就是0,1,2,3,4,5的父亲节点都是8,现在,将2孤立,现在让par[2] = id++,(id是从2*n开始的,他代表额外的新的未使用过的父亲节点),par[2] = 12,但是其他的点的父亲还是8,所以就达到了可以孤立点的目的,这是一种极为巧妙的方法。具体还是详见代码

    代码:

     1 #include <stdio.h>
     2 #include <string.h>
     3 
     4 const int N = 100005;
     5 const int M = 1000005;
     6 
     7 int par[N+N+M];
     8 bool vis[N+N+M];
     9 
    10 int fin(int x)
    11 {
    12     if (x == par[x]) return x;
    13     else return par[x] = fin(par[x]);
    14 }
    15 
    16 void unit(int x,int y)
    17 {
    18     x = fin(x);
    19     y = fin(y);
    20 
    21     if (x != y) par[x] = y;
    22 }
    23 
    24 int main()
    25 {
    26     int n,m;
    27 
    28     int cas = 0;
    29 
    30     while (scanf("%d%d",&n,&m) != EOF)
    31     {
    32         if (m == 0 && n == 0) break;
    33 
    34         printf("Case #%d: ",++cas);
    35 
    36         memset(vis,0,sizeof(vis));
    37 
    38         for (int i = 0;i < n;i++)
    39             par[i] = i + n;
    40 
    41         for (int i = n;i < n + n + m;i++)
    42             par[i] = i;
    43 
    44         int id = n + n;
    45 
    46         for (int i = 0;i < m;i++)
    47         {
    48             char op;
    49             int x,y;
    50 
    51             scanf(" %c%d",&op,&x);
    52 
    53             if (op == 'M')
    54             {
    55                 scanf("%d",&y);
    56 
    57                 unit(x,y);
    58             }
    59             else
    60             {
    61                 par[x] = id++;
    62             }
    63         }
    64 
    65         int ans = 0;
    66 
    67         for (int i = 0;i < n;i++)
    68         {
    69             if (!vis[fin(i)])
    70             {
    71                 ans++;
    72                 vis[fin(i)] = 1;
    73             }
    74         }
    75 
    76         printf("%d
    ",ans);
    77     }
    78 
    79     return 0;
    80 }
  • 相关阅读:
    Mac新手必看教程——轻松玩转Mac OS
    《图解 HTTP》 学习笔记
    在浏览器输入 URL 回车之后发生了什么(超详细版)
    VMware Ubuntu 19最新安装详细过程
    【学习笔记】第八章 python3核心技术与实践--条件与循环
    【学习笔记】第七章 python3核心技术与实践--输入与输出
    【学习笔记】第六章 python核心技术与实践--深入浅出字符串
    Prometheus搭建
    java---yml文件配置
    Nginx一个server配置多个location(使用alias)
  • 原文地址:https://www.cnblogs.com/kickit/p/7211324.html
Copyright © 2020-2023  润新知