POJ 1611 - The Suspects - Union-Find
阿新 • • 發佈:2021-10-10
POJ 1611 - The Suspects
描述
嚴重急性呼吸系統綜合症(SARS)是一種病因不明的非典型肺炎,在2003年3月中旬被確認為全球性威脅。
為了儘量減少對他人的傳播,最好的策略是將疑似者與其他人分開。
在不傳播疾病的大學(NSYSU)中,有很多學生群體。同一組的學生經常互相交流,一個學生可以加入幾個組。
為了防止非典型肺炎的傳播,NSYSU收集了所有學生團體的成員名單,並在其標準操作程式(SOP)中制定了以下規則:
一旦一個小組的成員是疑似者,這個小組的所有成員都是疑似者。
然而,他們發現,當一個學生被認定為疑似者時,要找出所有的疑似者並不容易。你的工作是寫一個程式找出所有疑似者。
輸入
輸入檔案包含幾個案例。每個測試用例從一行中的兩個整數n和m開始,其中n是學生數,m是組數。
你可以假設0<n<=30000和0<=m<=500。每個學生都用一個介於0和n−1之間的唯一整數來編號,最初學生0被認為是所有案件的疑似者。
這一行後面是m個組的成員列表,每個組一行。每一行都以一個整數k開始,表示組中的成員數。在成員數之後,有k個整數代表這個組中的學生。
一行中的所有整數至少用一個空格隔開。
n=0且m=0的case表示輸入結束,不需要處理。
輸出
對於每個案例,輸出一行中的疑似者數量。
思路: 並查集
1:一個組內只要有人疑似,就整組疑似,所以同組的合併;
2:用陣列記錄疑似個數,合併的時候,個數累加;
3:合併時小點往大點上合併,所以大點的個數包含所有子節點的個數;
4:只為0號已被認為是疑似者,所以要求所有涉及0的點的個;
5:由於從小到大合併,同組內,最大節點就是0的根節點,且該點個數包含此組所有人數,該根節點再往上找,可找到它所涉及的所有點的根節點,此點的個數,即為最終答案;
6:find(0)是從0開始一層層找到根節點,即最大的節點,suspectCnt[find(0)]是最大點的個數,即為所有疑似者個數
package basic_data_structure; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.StringTokenizer; /** * @author XA-GDD * ** 思路: 並查集, * 1:一個組內只要有人疑似,就整組疑似,所以同組的合併; * 2:用陣列記錄疑似個數,合併的時候,個數累加; * 3:合併時小點往大點上合併,所以大點的個數包含所有子節點的個數; * 4:只為0號已被認為是疑似者,所以要求所有涉及0的點的個; * 5:由於從小到大合併,同組內,最大節點就是0的根節點,且該點個數包含此組所有人數,該根節點再往上找,可找到它所涉及的所有點的根節點,此點的個數,即為最終答案; * 6:find(0)是從0開始一層層找到根節點,即最大的節點,suspectCnt[find(0)]是最大點的個數,即為所有疑似者個數 * */ public class D_TheSuspects { static int N,M,K; static int _Max_Size = 30005; static int [] parent = new int[_Max_Size];; static int [] suspectCnt = new int[_Max_Size];; public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String str; StringTokenizer st; while((str = br.readLine()) != null) { st = new StringTokenizer(str); N = Integer.parseInt(st.nextToken()); M = Integer.parseInt(st.nextToken()); if(N==0 && M==0) break; for(int i=0;i<N;i++) { parent[i] = i; suspectCnt[i] = 1; } for(int i=0;i<M;i++) { st = new StringTokenizer(br.readLine()); K = Integer.parseInt(st.nextToken()); int firstNo = Integer.parseInt(st.nextToken()); for(int j=1;j<K;j++) { int nextNo = Integer.parseInt(st.nextToken()); union(firstNo,nextNo); } } System.out.println(suspectCnt[find(0)]); } } static void union(int a, int b) { int pa = find(a); int pb = find(b); if(pa==pb) return; if(pa>pb) { parent[pb] = pa; suspectCnt[pa] += suspectCnt[pb]; }else{ parent[pa] = pb; suspectCnt[pb] += suspectCnt[pa]; } } static int find(int n) { if(parent[n]==n) return n; return parent[n] = find(parent[n]); } }