• 南阳1022--合纵连横 (并查集+删点)


     

    合纵连横

    时间限制:1000 ms  |  内存限制:65535 KB
    难度:3
     
    描述

    乱世天下,诸侯割据。每个诸侯王都有一片自己的领土。但是不是所有的诸侯王都是安分守己的,实力强大的诸侯国会设法吞并那些实力弱的,让自己的领土面积不断扩大。而实力弱的诸侯王为了不让自己的领土被吞并,他会联合一些其他同样弱小的诸侯国,组成联盟(联盟不止一个),来共同抵抗那些强大的诸侯国。 强大的诸侯国为了瓦解这些联盟,派出了最优秀的间谍来离间他们,使一些诸侯国退出联盟。最开始,每个诸侯国是一个联盟。

    有两种操作

    1、U x y 表示x和y在同一个联盟。(0≤x,y<n)

    2、D x   表示x退出联盟。

     
    输入
    多组测试数据
    第一行两个数,n和m(1 ≤ n≤ 10^5, 1 ≤ m ≤10^5),分别表示诸侯国的个数和操作次数。
    接下来有m行操作
    输出
    输出联盟的个数
    样例输入
    5 7
    U 0 1
    U 1 2
    U 0 3
    D 0
    U 1 4
    D 2
    U 0 2
    10 1
    U 0 9
    样例输出
    Case #1: 2
    Case #2: 9
    上传者
    ACM_马振阳
    RE: 上午周赛出的这道题, 当时写了一半就发现不太对, 下午一看, 果然略坑;
    并查集删点操作对于孩子节点来说, 直接father[i] = i;  就可以了。 根节点不能用这种方法,所以就建立一个新数组。
    相当于把原来数组包含在里面一块进行操作, 根节点合并时 对新数组操作, 原来数组节点的删除也不会影响已经建立的关系。 删除的节点存为虚点,http://blog.csdn.net/a915800048/article/details/41703865
     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 using namespace std;
     5 int father[100010], set[100010 * 2], vis[100010 * 2];
     6 int n, m;
     7 void init()
     8 {
     9     for(int i = 0; i < n; i++)
    10     {
    11         father[i] = i; 
    12         set[i] = i;
    13     }
    14 }
    15 int find(int a)
    16 {
    17     int r, j, k;
    18     r = a;
    19     while(r != set[r])
    20         r = set[r];
    21     j = a;
    22     while(j != r)
    23     {
    24         k = set[j];
    25         set[j] = r; 
    26         j = k;
    27     }
    28     return r; 
    29 }
    30 void mercy(int a, int b)
    31 {
    32     int q = find(a);
    33     int p = find(b);
    34     if(q != p)
    35         set[q] = p;
    36 }
    37 int main()
    38 {
    39     int temp = 1; 
    40     while(~scanf("%d %d", &n, &m))
    41     {
    42         init();
    43         int dis = n;  //虚点; 
    44         for(int i = 0; i < m; i++)
    45         {
    46             char str[2];
    47             scanf("%s", str);
    48             if(str[0] == 'U')
    49             {
    50                 int a, b;
    51                 scanf("%d %d", &a, &b);
    52                 mercy(father[a], father[b]);
    53             }
    54             else
    55             {
    56                 int c;
    57                 scanf("%d", &c);
    58                 father[c] = dis;
    59                 set[dis] = dis;
    60                 dis++;
    61             }
    62         }
    63         int ans = 0;
    64         memset(vis, 0, sizeof(vis));
    65         for(int i = 0; i < n; i++)
    66         {
    67                 if(!vis[find(father[i])])
    68                 {
    69                     //printf("%d %d %d
    ", set[i], father[i], find(father[i]));
    70                     vis[find(father[i])] = 1;
    71                     ans++;
    72                 }
    73         }
    74         printf("Case #%d: %d
    ", temp++, ans);
    75     } 
    76     return 0;
    77 }
     
  • 相关阅读:
    页面跳转
    基于MCP2515的Linux CAN总线驱动程序设计(三)
    基于MCP2515的Linux CAN总线驱动程序设计(二)
    基于MCP2515的Linux CAN总线驱动程序设计(一)
    任意ASCII码格式信息的huffman tree压缩(编码)和解压(译码)
    转:Linux环境下段错误的产生原因及调试方法小结
    转:C语言中volatile关键字的作用 专家博客
    处理字节对齐
    转: sizeof,总结
    sizeof()用法汇总
  • 原文地址:https://www.cnblogs.com/soTired/p/4732896.html
Copyright © 2020-2023  润新知