WEEK6 周记 作业——并查集_戴好口罩
一、题意
1.简述
新型冠状病毒肺炎(Corona Virus Disease 2019,COVID-19),简称“新冠肺炎”,是指2019新型冠状病毒感染导致的肺炎。
如果一个感染者走入一个群体,那么这个群体需要被隔离!
小A同学被确诊为新冠感染,并且没有戴口罩!!!!!!
危!!!
时间紧迫!!!!
需要尽快找到所有和小A同学直接或者间接接触过的同学,将他们隔离,防止更大范围的扩散。
众所周知,学生的交际可能是分小团体的,一位学生可能同时参与多个小团体内。
请你编写程序解决!戴口罩!!
2.输入格式
多组数据,对于每组测试数据:
第一行为两个整数n和m(n = m = 0表示输入结束,不需要处理),n是学生的数量,m是学生群体的数量。0 < n <= 3e4 , 0 <= m <= 5e2
学生编号为0~n-1
小A编号为0
随后,m行,每行有一个整数num即小团体人员数量。随后有num个整数代表这个小团体的学生。
3.输出格式
输出要隔离的人数,每组数据的答案输出占一行
4.样例
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
Output
4
1
1
二、算法
主要思路
由提议可以看出这是一个典型的并查集题目。通过将有重合成员的群组合并来划分集合。最后划分完成之后找出与感染者同一集合的成员就是需要隔离的人员。
注意:可以在在find函数中进行巧妙的路径压缩
int find(int a){
if(st[a].first==a){
return a;
}
int root = find(st[a].first);
st[a].first = root;//路径压缩
return root;
}
否则有可能会超时。
find这个标识符最好不要用,可能会CE。max、min、y1(如果有头文件cmath的话)也最好不要用。
三、代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
pair<int,int> st[30010];
int find(int a){
if(st[a].first==a){
return a;
}
int root = find(st[a].first);
st[a].first = root;
return root;
}
int unit(int a,int b){
if(st[a].second<st[b].second)
swap(a,b);//保证a这棵树是节点最多的
st[b].first = a;
st[a].second += st[b].second;
return a;
}
int main()
{
while(1){
scanf("%d%d",&n,&m);
if(n==0&&m==0)
break;
for(int i=0;i<n;i++)
st[i] = {i,1};
for(int i=0;i<m;i++){
int num,j,flag;
scanf("%d",&num);
int stu1,stu2;
scanf("%d",&stu1);
for(int j=1;j<num;j++){
scanf("%d",&stu2);
int root1 = find(stu1);
int root2 = find(stu2);
if(root1!=root2)
stu1 = unit(root1,root2);
}
}
int root = find(0);
printf("%d\n",st[root].second);
}
return 0;
}