1. 程式人生 > 其它 >專題訓練3-圖論 - C - The Suspects(並查集)

專題訓練3-圖論 - C - The Suspects(並查集)

題意

2019冠狀病毒病(英語:Coronavirus disease 2019,縮寫:COVID-19 ),是一種由嚴重急性呼吸系統綜合症冠狀病毒2型(縮寫:SARS-CoV-2)引發的傳染病。此病在全球各國大規模爆發並急速擴散,成為人類歷史上致死人數最多的流行病之一。 很顯然,目前最好的辦法就是將所有可能的患者都隔離起來。 現在某高校正在排查可能的患者,這個高校中有多個社團,每個社團經常進行內部交流,一名學生可能會加入多個社團。學校認為一旦某個社團裡出現一名可疑患者,這整個社團的學生都被視為是可能的患者。 現在請你幫忙找到這所學校的所有可能的患者。

(題面漏了一句話:0號學生帶病毒。)

輸入格式

輸入檔案包含多組資料。

對於每組測試資料:

第一行為兩個整數n和m, 其中n是學生的數量, m是社團的數量。0 < n <= 30000,0 <= m <= 500。

接下來m行,每一行有一個整數k,代表社團中學生的數量。之後,有k個整數代表這個社團裡每個學生的編號(在0到n-1之間)。

n = m = 0表示輸入結束,不需要處理。

輸出格式

對於每組測試資料, 輸出可能的患者數目。

樣例

Input Output
100 4
2 1 2
5 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
4
1
1

思路

並查集模板題。
用0號學生做根節點,用陣列size[]維護樹的節點個數即可,0號學生記錄的size就是答案。

程式碼

#include <iostream>
#include <cstring>

using namespace std;

const int N = 30010;

int n, m, k;
int p[N], size[N];
int pre, cur;

int find(int x) {
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}

int main() {
    while (~scanf("%d%d", &n, &m) && !(!n&&!m)) {
        memset(p, 0, sizeof p), memset(size, 0, sizeof size);
        for (int i = 0; i < n; i ++ ) p[i] = i, size[i] = 1;

        for (int i = 0; i < m; i ++ ) {
            scanf("%d", &k);
            if (!k) continue;
            scanf("%d", &cur);

            for (int j = 1; j < k; j ++ ) {
                pre = cur;
                scanf("%d", &cur);

                if (j) {
                    if (find(pre) == find(cur)) continue;

                    size[find(pre)] += size[find(cur)];
                    p[find(cur)] = find(pre);
                }
            }
        }

        printf("%d\n", size[find(0)]);
    }

    return 0;
}