1. 程式人生 > >食物鏈(帶權並查集)

食物鏈(帶權並查集)

clu style org 之間 i++ init esc rip 但是

題目鏈接:http://poj.org/problem?id=1182

題目:

Description

動物王國中有三類動物A,B,C,這三類動物的食物鏈構成了有趣的環形。A吃B, B吃C,C吃A。
現有N個動物,以1-N編號。每個動物都是A,B,C中的一種,但是我們並不知道它到底是哪一種。
有人用兩種說法對這N個動物所構成的食物鏈關系進行描述:
第一種說法是"1 X Y",表示X和Y是同類。
第二種說法是"2 X Y",表示X吃Y。
此人對N個動物,用上述兩種說法,一句接一句地說出K句話,這K句話有的是真的,有的是假的。當一句話滿足下列三條之一時,這句話就是假話,否則就是真話。
1) 當前的話與前面的某些真的話沖突,就是假話;
2) 當前的話中X或Y比N大,就是假話;
3) 當前的話表示X吃X,就是假話。
你的任務是根據給定的N(1 <= N <= 50,000)和K句話(0 <= K <= 100,000),輸出假話的總數。

Input

第一行是兩個整數N和K,以一個空格分隔。
以下K行每行是三個正整數 D,X,Y,兩數之間用一個空格隔開,其中D表示說法的種類。
若D=1,則表示X和Y是同類。
若D=2,則表示X吃Y。

Output

只有一個整數,表示假話的數目。

Sample Input

100 7
1 101 1 
2 1 2
2 2 3 
2 3 3 
1 1 3 
2 3 1 
1 5 5

Sample Output

3

思路:用一個3*N的數組來維護他們之間的關系,x+n為x的捕食者,x+2*n為x的獵物,因而當x與y的關系是同類的時候,需將他們+n、+2*n都一起合並為一個集合;當他們為捕食關系時,要將他們設為彼此的獵物。坑點為:不要用多組輸入!!!
代碼實現如下:
 1 #include <cstdio>
 2 
 3 const int maxn = 5e4 + 7;
 4 int n, k, ans;
 5 int d, x, y;
 6 int fa[maxn * 3], r[maxn * 3];
 7 
 8 void init(int
n) { 9 for (int i = 0; i < n; i++) { 10 fa[i] = i; 11 r[i] = 0; 12 } 13 } 14 15 int fi(int x) { 16 return fa[x] == x ? x : fa[x] = fi(fa[x]); 17 } 18 19 void unite(int x, int y) { 20 int p1 = fi(x), p2 = fi(y); 21 if (p1 == p2) return; 22 if (r[p1] > r[p2]) { 23 fa[p2] = p1; 24 } else { 25 fa[p1] = p2; 26 if (r[p1] == r[p2]) r[p2]++; 27 } 28 } 29 30 bool check(int x, int y) { 31 return fi(x) == fi(y); 32 } 33 34 int main() { 35 scanf("%d%d", &n, &k); 36 init(3 * n); 37 ans = 0; 38 for (int i = 0; i < k; i++) { 39 scanf("%d%d%d", &d, &x, &y); 40 x = x - 1, y = y - 1; 41 if (x < 0 || x >= n || y < 0 || y >= n) { 42 ans++; 43 continue; 44 } 45 if (d == 1) { 46 if (check(x, n + y) || check(x, 2 * n + y)) { 47 ans++; 48 } else { 49 unite(x, y); 50 unite(n + x, n + y); 51 unite(2 * n + x, 2 * n + y); 52 } 53 } else { 54 if (check(x, y) || check(x, y + 2 * n) || x == y) { 55 ans++; 56 } else { 57 unite(x, n + y); 58 unite(x + n, y + 2 * n); 59 unite(x + 2 * n, y); 60 } 61 } 62 } 63 printf("%d\n", ans); 64 return 0; 65 }

食物鏈(帶權並查集)