题目大意:n个学生分成m组,如果一个学生感染了病毒,他同组的学生就都感染了,开始时0号学生已感染,问有多少人感染
输入:(可以有很多case,输入以0 0结束)
第i个case的n m( 0 < n <= 30000 ,0 <= m <= 500)
第j组包含的人数k 每个学生的编号(空格分隔)
输出:第i个case的感染人数
分析:利用并查集(在同一个并查集中的点不能连线)。处理每个组时,从第二个学生开始,每个人都和第一个学生合并,最后循环n个人判断每个人是否在0为根的并查集中,并计数。
代码:转载自http://blog.csdn.net/lmfqyj/article/details/51357443
- #include<cstdio>
- using namespace std;
- int a[30001],pre[30001]; //a储存结点权值,pre储存父节点
- int find(int x)
- {
- if(pre[x]==x)
- return x;
- else
- return pre[x]=find(pre[x]); //返回x的根节点
- }
- void mix(int x, int y)
- {
- int fx = find(x), fy = find(y); //找xy分别所在的根节点
- if (fx != fy) //不在同一并查集
- pre[fy] = fx; //合并(连线)
- }
- int main()
- {
- //freopen("C:\\in.txt","r",stdin);
- int n,m;
- while (scanf("%d%d", &n, &m) != EOF && (n || m))
- {
- int sum = 0;
- for (int i = 0; i < n; i++) //初始化
- pre[i] = i;
- for (int i = 0; i < m; i++)
- {
- int k;
- scanf("%d", &k);
- if (k >= 1)
- {
- scanf("%d", &a[0]);
- for (int j = 1; j < k; j++)
- {
- scanf("%d", &a[j]);
- mix(a[0], a[j]);
- }
- }
- }
- for (int i = 0; i < n; i++)
- if (find(i) ==pre[0])
- sum++;
- printf("%d\n", sum);
- }
- return 0;
- }