poj1182 食物链(带权并查集)

题目链接

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

posted @ 2017-12-01 22:13  ColdCode  阅读(173)  评论(0编辑  收藏  举报
AmazingCounters.com