食物链

来源:互联网 发布:tensorflow java接口 编辑:程序博客网 时间:2024/04/24 03:31

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 71 101 1 2 1 22 2 3 2 3 3 1 1 3 2 3 1 1 5 5

Sample Output

3 
开始时的思路是用并查集保存每一组已经能够确定在同一组的动物编号,就是如果x,y已经确定在同一组,就有p[x] == p[y],
这样有一个缺陷,就是在插入后维护起来相当麻烦,我利用prey[i]保存i同类的猎物,predator[i]保存i同类的的捕食者。
相当麻烦的实现了维护,可是还是过不了。
另一种思路是:打包。
把已经确定的信息打包起来,如下:
如果 “x吃y” 已经确定,那么如果x属于A(B,C),y一定属于B(C,A)。如果“x与y同类”已经确定,那么如果x属于A(B,C),则y一定属于A(B,C)。
由此:定义一个概念 --- 空间。在同一个空间下的两个命题等价。如果“x吃y”为真,则命题“x∈A”和“x∈B”在同一个空间下,命题“x∈B”与“x∈C”在同一个空间下,依此。当“x与y同类”时,也同理可以知道哪些命题一定在同一个空间下。
接下来,要判断给定的一个命题是否为假,就要看是否能够在同一个空间下找到该命题的一个否定。
如:判断命题p : “x吃y”,则如果“x属于A 且 y属于A”为真时,或者“x属于A 且 y属于C”为真时,p为假。
不用去判断“x属于B 且 y属于B”,“x属于B 且 y属于A”等,因为在一个命题不能被判为假时,它的各个等价命题都被加入到对应的空间。
具体实现:
命题“x∈A”数字化为x+A,其它同理。
代码如下:
//查找对应命题所在的空间编号
int find(int a){return a == at[a] ? a : at[a] = find(at[a]);}//合并两个空间中的所有命题void merge(int a, int b){int x = find(a), y = find(b);at[x] = y;}bool judge(int d, int x, int y, int n){if(x <= 0 || y <= 0 || x > n || y > n)return false;if(d == 1){if(find(x+A) == find(y+B) || find(x+A) == find(y+C))return false;merge(x+A, y+A);merge(x+B, y+B);merge(x+C, y+C);}else{if(find(x+A) == find(y+A) || find(x+A) == find(y+C))return false;merge(x+A, y+B);merge(x+B, y+C);merge(x+C, y+A);}return true;}

0 0
原创粉丝点击