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
AC代码:
#include <iostream>
#include<cstdio>
using namespace std;
int father[30001],sum[30001];
int f(int n)
{
if(n!=father[n])
father[n]=f(father[n]);
return father[n];
//或return father[n]==n?n:father[n]=f(father[n]);
}//获取根节点
void merge(int x,int y)
{
int fx,fy;
fx=f(x);
fy=f(y);
if(fx<fy)
{
father[fy]=fx;
sum[fx]+=sum[fy];
}
if(fx>fy)
{
father[fx]=fy;
sum[fy]+=sum[fx];
}
} //合并两个元素所在的集合
//判断两个元素是否属于同一个集合
int main()
{
int n,m,k,p,q;
while(~scanf("%d%d",&n,&m))
{
for(int i=0;i<=n;i++)
{
father[i]=i;
sum[i]=1;
}//初始化
if(n==0&&m==0)break;
for(int i=0;i<m;i++)
{
scanf("%d%d",&k,&p);
for(int j=1;j<k;j++)
{
scanf("%d",&q);
merge(p,q);
}
}
printf("%d
",sum[0]);//与0有染的人的个数
}
return 0;
}
分析:本题可以用并查集解决,就是让你求有多少人与0号有关
心得:之前没见过这种题目,读了很久也没读懂问题的实质,然后自己去网上搜了一下,又看了一下并查集的概念和算法,最后还是将这个题做了出来,但是感觉对并查集还是不是很懂。这也是一个模板题。