POJ 1182 食物链

食物链
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 34498   Accepted: 10026

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

一道经典的并查集问题
今天下午自学并查集,基本上是照着资料抄了这道题,不过收获颇丰
本题中的重点在于关系的确定,有如下公式:
  如果a对c的关系为:a.relation,b对c的关系为b.relation,那么a对b的关系为(a.relation-b.relation+3)%3
  加3是为了防止前面的做差变成负数,导致取模后符号出现问题
  由此公式可以推到出Find(),Merge()函数中的几个关系式
Find()中还用到了一个技巧就是要记录他的前任父亲:
  由于在两个集合合并时只能调整祖先的关系,而无法调整叶子节点的关系,所以在Find()函数中每次要记录该叶子节点的前任父亲,然后根据更新后的前任父亲状态更新自身的状态

代码如下,用了Codeblocks,代码整洁多了^_^

 1 #include<stdio.h>
 2 
 3 typedef struct sth
 4 {
 5     int relation;
 6     long father;
 7 } NODE;
 8 
 9 long n, k;
10 NODE animal[50001];
11 
12 void MakeSet()
13 {
14     int i;
15 
16     for (i = 1; i <= n; i++)
17     {
18         animal[i].relation = 0;
19         animal[i].father = i;
20     }
21 }
22 
23 void Merge (long a, long b, long x, long y, int d)
24 {
25     animal[a].father = b;
26     animal[a].relation = (animal[y].relation - animal[x].relation + 2 + d) % 3;
27 }
28 
29 long Find (long x)
30 {
31     long pre_father;
32 
33     if (x != animal[x].father)
34     {
35         pre_father = animal[x].father;
36         animal[x].father = Find (animal[x].father);
37         animal[x].relation = (animal[x].relation + animal[pre_father].relation) % 3;
38     }
39 
40     return animal[x].father;
41 }
42 
43 int main()
44 {
45     int d;
46     long a, b, x, y, sum = 0;
47 
48     scanf ("%ld %ld", &n, &k);
49 
50     MakeSet();
51 
52     while (k--)
53     {
54         scanf ("%d %ld %ld", &d, &x, &y);
55         if ( (x > n) || (y > n) || ( (x == y) && (d == 2)))
56             sum++;
57         else
58         {
59             a = Find (x);
60             b = Find (y);
61             if ( (a == b) && ( (animal[x].relation - animal[y].relation + 3) % 3 != d - 1))
62                 sum++;
63             else if (a != b)
64                 Merge (a, b, x, y, d);
65         }
66     }
67     printf ("%ld\n", sum);
68     return 0;
69 }
[C]

 

posted @ 2013-05-21 22:28  ~~Snail~~  阅读(248)  评论(0编辑  收藏  举报