poj1182 食物链

题意:

三类动物A、B、C,A吃B,B吃C,C吃A。
给出K句话来描述N个动物(各属于A、B、C三类之一)之间的关系,格式及意义如下:
1 X Y:表示X与Y是同类;
2 X Y:表示X吃Y。
K句话中有真话有假话,当一句话满足下列三条之一时,这句话就是假话,否则就是真话。1)当前的话与前面的某些真的话冲突,就是假话;2)当前的话中X或Y比N大,就是假话;3)当前的话表示X吃X,就是假话。
求假话的总数。

输入:
第一行是两个整数N和K,以一个空格分隔。以下K行每行是三个正整数D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。若D=1,则表示X和Y是同类。若D=2,则表示X吃Y。
输出:
只有一个整数,表示假话的数目。
约束条件:
1 <= N <= 50000,0 <= K <= 100000。

思路:

并查集中的元素并不是动物,而是每只动物属于某种类别的信息。

具体来说,对于每只动物i创建i-A,i-B,i-C,并用这3*N个元素建立并查集。i-x表示“i属于种类x”。并查集里的每一个组内表示所有元素代表的情况同时发生或不发生。

对于x和y属于同一种类这种信息,合并x-A和y-A,x-B和y-B,x-C和y-C;

对于x吃y这种信息,合并x-A和y-B,x-B和y-C,x-C和y-A。

合并之前检查是否矛盾并计数即可。

实现:

 1 #include <iostream>
 2 #include <cstdio>
 3 #define MAXN 50000
 4 using namespace std;
 5 int a[MAXN + 10];
 6 int par[3 * MAXN + 10];
 7 int ran[3 * MAXN + 10];
 8 void init(int n)
 9 {
10     for (int i = 0; i <= n; i++)
11     {
12         par[i] = i;
13         ran[i] = 0;
14     }
15 }
16 int find(int x)
17 {
18     if (x == par[x])
19         return x;
20     return par[x] = find(par[x]);
21 }
22 void unite(int x, int y)
23 {
24     x = find(x);
25     y = find(y);
26     if (x == y)
27     {
28         return;
29     }
30     if (ran[x] < ran[y])
31     {
32         par[x] = y;
33     }
34     else
35     {
36         par[y] = x;
37         if (ran[x] == ran[y])
38         {
39             ran[x]++;
40         }
41     }
42 }
43 bool same(int x, int y)
44 {
45     return find(x) == find(y);
46 }
47 int main()
48 {
49     int n, k, t, x, y;
50     cin >> n >> k;
51     int cnt = 0;
52     init(3 * n);
53     for (int i = 0; i < k; i++)
54     {
55         scanf("%d %d %d", &t, &x, &y);
56         if (x <= 0 || x > n || y <= 0 || y > n)
57         {
58             cnt++;
59             continue;
60         }
61         x--;
62         y--;
63         if (t == 1)
64         {
65             if (same(x + n, y + 2 * n) || same(x + n, y))
66             {
67                 cnt++;
68             }
69             else
70             {
71                 unite(x, y);
72                 unite(x + n, y + n);
73                 unite(x + 2 * n, y + 2 * n);
74             }
75         }
76         else
77         {
78             if (same(x + n, y) || same(x + 2 * n, y + 2 * n))
79             {
80                 cnt++;
81             }
82             else
83             {
84                 unite(x, y + n);
85                 unite(x + n, y + 2 * n);
86                 unite(x + 2 * n, y);
87             }
88         }
89     }
90     cout << cnt << endl;
91     return 0;
92 }
原文地址:https://www.cnblogs.com/wangyiming/p/6357902.html