POJ-1611 The Suspects

Description

严重急性呼吸系统综合症( SARS), 一种原因不明的非典型性肺炎,从2003年3月中旬开始被认为是全球威胁。为了减少传播给别人的机会, 最好的策略是隔离可能的患者。
在Not-Spreading-Your-Sickness大学( NSYSU), 有许多学生团体。同一组的学生经常彼此相通,一个学生可以同时加入几个小组。为了防止非典的传播,NSYSU收集了所有学生团体的成员名单。他们的标准操作程序(SOP)如下:
一旦一组中有一个可能的患者, 组内的所有成员就都是可能的患者。
然而,他们发现当一个学生被确认为可能的患者后不容易识别所有可能的患者。你的工作是编写一个程序, 发现所有可能的患者。
 

Input

输入文件包含多组数据。
对于每组测试数据:
第一行为两个整数n和m, 其中n是学生的数量, m是团体的数量。0 < n <= 30000,0 <= m <= 500。
每个学生编号是一个0到n-1之间的整数,一开始只有0号学生被视为可能的患者。
紧随其后的是团体的成员列表,每组一行。
每一行有一个整数k,代表成员数量。之后,有k个整数代表这个群体的学生。一行中的所有整数由至少一个空格隔开。
n = m = 0表示输入结束,不需要处理。

Output

对于每组测试数据, 输出一行可能的患者。

Sample Input

100 4
2 1 2
5 10 13 11 12 14
2 0 1
2 99 2
200 2
1 5
5 1 2 3 4 5
1 0
0 0

Sample Output

4
1
1


这是一个简单并查集问题,我们给每个团中所有成员合并在一个根节点,这样如果两个团体有相同的人,那么这两个团体中所有人的根节点相同。
然后就只要查找0和其他人得根节点是否相同就可以了;


#include<cstdio>
#include<cstring>
using namespace std;
int n,m,k,father[30010];
int find(int x)
{
    int y,a,b;
    y=x;
    while (y!=father[y]) y=father[y];
    while (x!=father[x])
    {
        a=father[x];
        father[x]=y;
        x=a;
    }
    return y;
}
void un(int x,int y)
{
    int rx=find(x);
    int ry=find(y);
    if (rx==ry) return ;
    father[rx]=ry;
}
int main()
{
   int a,b,i,sum;
   while (~scanf("%d%d",&n,&m))
   {
       if (n==0&&m==0) break;
       sum=0;
       for (i=0;i<n;i++)
       father[i]=i;
       while (m--)
       {
           scanf("%d",&k);
           if (k>=1) scanf("%d",&a);
           k--;
           while (k--)
           {
               scanf("%d",&b);
               un(a,b);
           }
       }
       for (i=0;i<n;i++)
       {
           if (find(0)==find(i))
             sum++;
       }
       printf("%d
",sum);
   }
   return 0;
}
原文地址:https://www.cnblogs.com/pblr/p/4680884.html