并查集之The Suspects

在不传播疾病的大学(NSSU)中,有很多学生群体。同一组的学生经常互相交流,学生可以加入几个小组。为了防止SARS可能传播,NSUSU收集所有学生组的成员名单,并在其标准操作程序(SOP)中执行以下规则。

一旦一个小组中的成员是嫌疑犯,该组中的所有成员都是嫌疑犯。

然而,他们发现,当一个学生被认定为嫌疑犯时,不容易识别所有的嫌疑犯。你的工作是写一个程序,找出所有嫌疑犯。

input

输入文件包含几种情况。每个测试用例从两个整数n和m开始,其中n是学生的数目,m是组的数目。你可以假设0<n<=30000,0 <=m <=500。每个学生都有0到N到1之间的一个唯一的整数,最初学生0被认定为所有案件中的嫌疑犯。这一行后面是M组成员列表,每组一行。每一行都以整数k开头,表示该组中成员的数目。根据成员的数量,有K整数代表这个组的学生。一行中的所有整数由至少一个空间分隔。

n=0,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
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int per[30100], num[30100],a[30100];
int find(int x)
{
    if(x==per[x])
        return x;
    return find(per[x]);
}
void join(int x, int y)
{
    int fx = find(x);
    int fy = find(y);
    if(fx!= fy)
    {
        per[fx]=fy;
        num[fy]+=num[fx];
    }
}

int main ()
{
    int n,m,i,k;
    while(scanf("%d%d",&n,&m))
    {
        if(n==0&&m==0)
            break;
        for(i=0;i<n;++i)
        {
            per[i]=i;
            num[i]=1;
        }
        while(m--)
        {
            int t;
            scanf("%d", &t);
            for(i=0;i < t; ++i)
            {
                scanf("%d", &a[i]);
            }
            for(i=0 ; i<t-1;i++)
                join(a[i], a[i + 1]);//把同一小组的归类 使他有共同的祖先
        }
        k=find(0);
        printf("%d\n", num[k]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/sinat_39654987/article/details/81411182