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

poj1182 食物鏈(帶權並查集)

txt amp 帶權並查集 htm 代碼 || blog 參考 oid

題目鏈接

http://poj.org/problem?id=1182

思路

前面做的帶權並查集的權值記錄該結點與其父結點是否是同一類,只有兩種取值情況(0,1),在這題中某結點a和其父結點b的取值共有三種情況:a和b同類;a被b吃;a吃b,對應三種情況,r[a]的取值分別為0,1,2。這題的難點是遞推公式,路徑壓縮遞推公式為r[x] = (r[x] + r[t]) % 3,合並集合遞推公式為r[ra] = (3 - r[a] + d - 1 + r[b]) % 3,遞推公式形式的推導可以參考這篇文章。

代碼

 1 #include <cstdio>
 2 
 3 const
int N = 500000 + 10; 4 int p[N]; 5 int r[N]; 6 7 void make_set(int n) 8 { 9 for (int i = 1;i <= n;i++) 10 { 11 p[i] = -1; 12 r[i] = 0; 13 } 14 } 15 16 int find_root(int x) 17 { 18 if (p[x] == -1) 19 return x; 20 21 int t = p[x]; 22 p[x] = find_root(p[x]);
23 r[x] = (r[x] + r[t]) % 3; //路徑壓縮遞推公式 24 return p[x]; 25 } 26 27 int union_set(int d, int a, int b) 28 { 29 int ra = find_root(a); 30 int rb = find_root(b); 31 32 if (ra != rb) //a,b不在同一集合,合並 33 { 34 p[ra] = rb; 35 r[ra] = (3 - r[a] + d - 1 + r[b]) % 3
; //合並集合遞推公式 36 return 0; 37 } 38 else 39 { 40 if ((r[a] + 3 - r[b]) % 3 != d - 1) 41 return 1; 42 else return 0; 43 } 44 return 0; 45 } 46 47 int main() 48 { 49 //freopen("poj1182.txt", "r", stdin); 50 int n, k; 51 scanf("%d%d", &n, &k); 52 make_set(n); 53 int d, x, y; 54 int ans = 0; 55 for (int i = 0; i < k;i++) 56 { 57 scanf("%d%d%d", &d, &x, &y); 58 if (x > n || y > n || (d == 2 && x == y)) 59 ans++; 60 else ans+=union_set(d, x, y); 61 } 62 printf("%d\n", ans); 63 return 0; 64 }

參考:

1、http://www.voidcn.com/article/p-mwvpmony-qx.html

2、https://www.cnblogs.com/zhuanzhuruyi/p/5863738.html

poj1182 食物鏈(帶權並查集)