食物链
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 54779 | Accepted: 16061 |
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),输出假话的总数。
现有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。
以下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
Source
解这个题的方法很巧妙, 看了两种不同题解, 有一种不理解公式是怎么推出来的 ,据说是利用向量。 So--- 用了种比较巧的方法。
题解(参考别人):
别人好像是参考的《挑战程序设计竞赛》88页。
对于每只动物创建三个元素 i --> a; i --> b; i --> c; 用3*n 个元素建立并查集, 此并查集维护信息如下:
<1>: i --> x: 该动物属于哪个种群;
<2>: 并查集中两个元素同时发生或同时不发生。
可以把<0, n>, <n, n+n>, <n+n, n+n+n> 分别看作A, B, C三个种群。
①如果两只动物属于同一种群, 可以在集合中加入边 <a, b>, <a+n, b+n>, <a+2*n, b+2*n>;
②如果两只动物是捕食关系, 可以按照题目中信息在集合中+边 <a, b+n>; <a+n, b+2*n>; <a+2*n, b>;
题目中求的是假话的数量(重要信息都在题目中)。
这部分细心, 有点像模拟。
写了这么多, 感觉自己有点"虚", 碰到它, 不看题解, 估计也解不出来。
#include <cstdio> #include <cstring> #include <iostream> #define N 50001 using namespace std; int father[N*3]; void Init(int n) { for(int i = 1; i <= n; i++) father[i] = i; } int Find(int a) { if(a == father[a]) return a; else return father[a] = Find(father[a]); } void Mercy(int a, int b) { int Q = Find(a); int P = Find(b); if(Q != P) father[Q] = P; } void Solve(int n, int m) { int totAl = 0; for(int i = 1; i <= m; i++) { int T, x, y; scanf("%d%d%d", &T, &x, &y); if(x <= 0 || y <= 0 || x > n || y > n) { totAl++; continue; } if(T == 1) { if(Find(x) == Find(y + n) || Find(x) == Find(y + 2*n)) totAl++; else { Mercy(x, y); Mercy(x+n, y+n); Mercy(x+2*n, y+2*n); } } if(T == 2) { if(Find(x) == Find(y) || Find(x) == Find(y+2*n)) totAl++; else { Mercy(x, y+n); Mercy(x+n, y+2*n); Mercy(x+2*n, y); } } } printf("%d ", totAl); } int main() { int n, m; scanf("%d%d", &n, &m); Init(n*3); Solve(n, m); return 0; }