1. 程式人生 > >POJ_1703 Find them, Catch them 【並查集】

POJ_1703 Find them, Catch them 【並查集】

一、題面

POJ1703

二、分析

需要將並查集與向量法則相結合。par陣列用以記錄父節點,rank用以記錄與父節點的關係。如題意,有兩種關係,設定0是屬於同一個幫派,1表示不屬於同一個幫派。

運用並查集的時候判斷x,y時考慮幾種情況:

1.x與y父節點不相同:此時為不清楚兩者關係。

2.x與y父節點相同,rank的值也相同:兩者屬於同一幫派。

3.x與y父節點相同,rank的值不相同:兩者不屬於同一幫派。

要得到這個關係,需要在並查集的find函式內對各個點的rank和par的值進行不斷的更新。

對於rank,需要使用向量加法,如

$\overrightarrow{AB}+\overrightarrow {BC}=\overrightarrow {AC}$

結合題目就是例:x的父節點px,如果x與父節點的關係是rank[x],px與父節點的關係是rank[px],那麼x與par[px]的關係就是

$(rank[x] + rank[px])\%2$

其他的推理類似。

在find的路徑壓縮時,注意把rank關係進行更新即可,在union時涉及到x,y與它們的父節點px,py的rank值更新,其實原理相同。

三、AC程式碼

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <fstream>
 4 
 5 using namespace
std; 6 7 const int MAXN = 1e5+4; 8 int par[MAXN]; 9 int Rank[MAXN]; 10 11 void init() 12 { 13 for(int i = 0; i < MAXN; i++) 14 { 15 par[i] = i; 16 Rank[i] = 0; 17 } 18 } 19 20 int find(int x) 21 { 22 if(par[x] == x) 23 return x; 24 int px = par[x];
25 par[x] = find(par[x]); 26 Rank[x] = (Rank[px]+Rank[x])%2; 27 return par[x]; 28 } 29 30 void Union(int x, int y) 31 { 32 int px = find(x); 33 int py = find(y); 34 if(px == py) 35 return; 36 par[px] = py; 37 Rank[px] = (Rank[x]+1+Rank[y])%2; 38 } 39 40 int main() 41 { 42 //freopen("input.txt", "r", stdin); 43 //freopen("out.txt", "w", stdout); 44 int T, M, N, x, y; 45 char op; 46 47 while(scanf("%d", &T)!=EOF) 48 { 49 50 while(T--) 51 { 52 init(); 53 scanf("%d %d", &N, &M); 54 for(int i = 0; i < M; i++) 55 { 56 getchar(); 57 scanf("%c %d %d", &op, &x, &y); 58 if(op == 'A') 59 { 60 int px = find(x); 61 int py = find(y); 62 if(px != py) 63 { 64 puts("Not sure yet."); 65 } 66 else 67 { 68 if(Rank[x] == Rank[y]) 69 puts("In the same gang."); 70 else 71 puts("In different gangs."); 72 } 73 } 74 else 75 { 76 Union(x, y); 77 } 78 } 79 } 80 } 81 return 0; 82 }
View Code