zoukankan      html  css  js  c++  java
  • poj 1611 The Suspects 解题报告

    题目链接:http://poj.org/problem?id=1611

    题意:给定n个人和m个群,接下来是m行,每行给出该群内的人数以及这些人所对应的编号。需要统计出跟编号0的人有直接或间接关系的人数总共有多少。

           这又是一条并查集的应用。难点是如何统计出与0有关系的总人数,即包含0的集合内元素的总个数。我的方法是用了两次merge,第一次merge单纯地将同一群内的元素连边,当然该群内的元素的祖先有可能是别的群内的元素,连边的规则是大的元素指向小的元素;第二次merge则把第一次筛选出来的集合中将元素与它的祖先再合并。目的是为了每一个集合内的元素都指向同一个代表。

           以第一个数据测试来说,第二行的 2  1  2,把编号1和2的人连边,此时p[1] = 1, p[2] = 1;

    第四行的  2   0   1,把编号0和1的人连边,此时p[0] = 0,p[1]  = 0;第五行的 2  99  2,结果p[99] = 0,p[2] = 1。(p[99] 指向元素2的祖先,而2的祖先1的祖先为0,因此p[99] = 0)。处理完问题出现了,第一次merge并不能使p[2]指向0,它还是保持1,因此第二次merge就有必要设置了。它使得p[2] = 0。由于代表为0的集合上所有的元素都指向0,因此最后统计哪些祖先是0的集合个数就是答案了。

     1 #include <iostream>
     2 using namespace std;
     3 
     4 const int maxn = 30000 + 5;
     5 int p[maxn];
     6 
     7 int find(int x)
     8 {
     9     while (x != p[x])
    10         x = p[x];
    11     return x;
    12 }
    13 
    14 void merge(int x, int y)
    15 {
    16     int fx = find(x);
    17     int fy = find(y);
    18     if (fx > fy)        // 从一开始就保证大的元素指向小的元素,即大的元素的祖先是小的元素
    19         p[fx] = fy;
    20     else
    21         p[fy] = fx;
    22 }
    23 
    24 void merge1(int x, int y)      // 第二次merge很关键
    25 {
    26     int fx = find(x);
    27     int fy = find(y);
    28     if (fx > fy)        // 数组下标与第一次merge是不同的!!!
    29         p[x] = fy;
    30     else
    31         p[y] = fx;
    32 }
    33 
    34 int main()
    35 {
    36     int i, j, n, m, t, x, k;
    37     while (scanf("%d%d", &n, &m) != EOF && (m || n))
    38     {
    39         if (m == 0)     // 特殊情况没有群,此时只有0这个学生是嫌疑犯
    40             printf("1\n");
    41         else
    42         {
    43             for (i = 0; i < n; i++)
    44             {
    45                 p[i] = i;
    46             }
    47             for (i = 0; i < m; i++)
    48             {
    49                 scanf("%d", &k);  
    50                 scanf("%d", &t);  // 每组中第一个人要单独输入,为了下面的merge操作方便     
    51                 for (j = 1; j < k; j++)
    52                 {
    53                     scanf("%d", &x);
    54                     merge(t, x);
    55         //            printf("p[%d] = %d, p[%d] = %d\n", t, p[t], x, p[x]);
    56                     t = x;
    57                 }
    58             }
    59             int cnt = 1;      // 编号为0这个人
    60             for (i = 1; i < n; i++)
    61             {
    62                 if (p[i] != i)    // 第一轮merge后的再一次处理
    63                 {
    64                     merge1(p[i], i);
    65             //        printf("p[%d] = %d\n", i, p[i]); 
    66                     if (p[i] == 0)
    67                         cnt++;
    68                 }
    69             }
    70             printf("%d\n", cnt);
    71         }
    72     }
    73     return 0;
    74 }

        

  • 相关阅读:
    mongodb的CRUD操作三
    mongodb的CRUD操作二查询
    mongodb的CRUD操作一
    python 全栈Day01 安装python
    sqlalchemy 无法显示中文的问题
    2017python学习的第九天,进程,线程协程
    2017python学习的第八天,socket的使用
    2017python学习的第七天,面向对象编程
    2017python学习的第六天,面向对象
    创建证书
  • 原文地址:https://www.cnblogs.com/windysai/p/3298819.html
Copyright © 2011-2022 走看看