题面:2019冠状病毒病(英语:Coronavirus disease 2019,缩写:COVID-19 ),是一种由严重急性呼吸系统综合症冠状病毒2型(缩写:SARS-CoV-2)引发的传染病。此病在全球各国大规模爆发并急速扩散,成为人类历史上致死人数最多的流行病之一。 很显然,目前最好的办法就是将所有可能的患者都隔离起来。 现在某高校正在排查可能的患者,这个高校中有多个社团,每个社团经常进行内部交流,一名学生可能会加入多个社团。学校认为一旦某个社团里出现一名可疑患者,这整个社团的学生都被视为是可能的患者。 现在请你帮忙找到这所学校的所有可能的患者。
Input
输入文件包含多组数据。
对于每组测试数据:
第一行为两个整数n和m, 其中n是学生的数量, m是社团的数量。0 < n <= 30000,0 <= m <= 500。
接下来m行,每一行有一个整数k,代表社团中学生的数量。之后,有k个整数代表这个社团里每个学生的编号(在0到n-1之间)。
n = m = 0表示输入结束,不需要处理。
Output
对于每组测试数据, 输出可能的患者数目。
Sample Input
100 4
2 1 2
6 11 13 50 12 14
2 0 1
2 99 2
200 2
1 5
6 5 6 7 8 9 10
1 0
0 0
Sample Output
4
1
1
思路:我们可以将题面翻译为:
1)求第0号患者所在集合的人数
2)求从第0号点(患者看成一个点)出发,求可以到达的点的数量,或者说与第0号点联通的点的数量
明显思路一应该用并查集来实现(即与第0号患者的父结点相同的点),思路二则是一般的连接图的遍历
具体看代码实现
AC代码
1)
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const int N = 3e4;
int fa[N + 5], a[N + 5];
int n, m, cnt, ans;
int query(int x)
{
if(x != fa[x]) fa[x] = query(fa[x]);
return fa[x];
}
int main()
{
while(1)
{
ans = 0;
scanf("%d%d", &n, &m);
if(!n && !m) break;
for(int i = 0; i <= n; ++i) fa[i] = i;
for(int i = 1; i <= m; ++i)
{
scanf("%d", &cnt);
if(!cnt) continue;
for(int i = 1; i <= cnt; ++i)
scanf("%d", &a[i]);
int r1 = query(a[1]);
for(int i = 2; i <= cnt; ++i)
{
int r2 = query(a[i]);
fa[r2] = r1;
}
}
int r1 = query(fa[0]);
for(int i = 0; i <= n; ++i)
{
if(query(fa[i]) == r1)
++ans;
}
printf("%d\n", ans);
}
return 0;
}
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;
const int N = 3e4, M = 5e2, NM = 10 * N;
int a[N + 1];
int n, m, cnt, ans, tot;
int fir[NM], nex[NM], ver[NM], que[2 * N + 5];
bool vis[N + 5];
void add(int x, int y)
{
nex[++tot] = fir[x]; fir[x] = tot; ver[tot] = y;//连接表存图
//printf("nex[%d] = %d, fir[%d] : %d, ver : %d\n", tot, nex[tot], x, fir[x], ver[tot]);
nex[++tot] = fir[y]; fir[y] = tot; ver[tot] = x;
//printf("nex[%d] = %d, fir[%d] : %d, ver : %d\n", tot, nex[tot], y, fir[y], ver[tot]);
}
int main()
{
while(1)
{
scanf("%d%d", &n, &m);
if(!n && !m) break;
memset(fir, 0, sizeof(fir)); memset(nex, 0, sizeof(nex));
memset(vis, 0, sizeof(vis));
tot = 0;
for(int k = 1; k <= m; ++k)
{
scanf("%d", &cnt);
for(int i = 1; i <= cnt; ++i)
scanf("%d", &a[i]);
for(int i = 1; i < cnt; ++i)
{
add(a[i], a[i + 1]);
}
}
int head = -1, tail = 0;
que[tail] = 0; ans = 0; vis[0] = 1;
while(head != tail)
{
++ans;
head = (head + 1) % (2 * N);
int u = que[head];
for(int i = fir[u], v; v = ver[i], i; i = nex[i])
{
if(!vis[v])
{
tail = (tail + 1) % (2 * N);
que[tail] = v; vis[v] = 1;
}
}
}
printf("%d\n", ans);
}
return 0;
}