【并查集】POJ1611病毒感染

一起学猫叫病毒( Miaomiaomiao Together), 是一种原因不明的流行性病毒。从去年起,一起学猫成为新一代校园毒品,听到一起学猫叫这首歌的人很有可能就会感染这种病毒。由于它传染性很强( 只要你周围有人唱一起学猫叫,你很有可能也会开始唱,并开始劝你的同学一起唱)它开始被认为是全球威胁。为了减少传播给别人的机会, 最好的策略是隔离可能的患者。
学校里有许多学生团体。同一组的学生经常彼此相通,一个学生可以同时加入几个小组。为了防止一起学猫叫病毒病毒的传播,cjluxk算法与程序设计协会收集了所有学生团体的成员名单。他们的标准操作程序如下:
一旦一组中有一个可能的患者, 组内的所有成员就都是可能的患者。
为了遏制这种病毒的传播,我们需要找到所有的患者。现在知道编号为0的如花妹妹(感染源)已经得了一起学猫叫病毒,请你设计程序 发现所有可能的患者。

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

思路

求同一连通分量中的结点个数,在并查集中再开一个size数组存储,注意同一连通分量中的结点个数存储在以它的根结点为下标的size元素。

代码

package uf;
import java.util.Scanner;
public class Poj1611 {
    private static class UF{
        private int[] parent;
        private byte[] rank;
        private int[] size;
        UF(int N){
            parent = new int[N];
            rank = new byte[N];
            // size[k]储存以k为根结点的连通分量中的结点个数,初始化为1
            size = new int[N];
            for(int i = 0; i < N; i++){
                parent[i] = i;
                size[i] = 1;
            }
        }
        private int find(int p){
            while (p != parent[p]){
                parent[p] = parent[parent[p]];
                p = parent[p];
            }
            return p;
        }
        public void union(int p, int q){
            int rootP = find(p), rootQ = find(q);
            if(rootP == rootQ) return;
            if(rank[rootP] < rank[rootQ]){
                parent[rootP] = rootQ;
                size[rootQ] += size[rootP];
            }else if(rank[rootP] > rank[rootQ]){
                parent[rootQ] = rootP;
                size[rootP] += size[rootQ];
            }else {
                parent[rootQ] = rootP;
                size[rootP] += size[rootQ];
                rank[rootP]++;
            }
        }
    }
    public static void main(String[] args){
        Scanner in = new Scanner(System.in);
        while (true){
            int m = in.nextInt(), n = in.nextInt();
            if(m == 0 && n == 0) break;
            UF uf = new UF(m);
            while (n-- > 0){
                int t = in.nextInt();
                int a, b;
                a = in.nextInt();
                while (--t > 0){
                    b = in.nextInt();
                    uf.union(a, b);
                    a = b;
                }
            }
            // 这里注意0不一定是它的连通分量的根结点。
            // 所以0的同一连通分量中的结点的个数存储在以它的根结点为索引的size数组中的元素。
            System.out.println(uf.size[uf.find(0)]);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/a617976080/article/details/88734470