当前位置: 代码迷 >> 综合 >> POJ - 1182 食物链
  详细解决方案

POJ - 1182 食物链

热度:57   发布时间:2023-12-08 08:17:13.0

一道十分有意思的题

动物王国中有三类动物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

题解:详见代码

#include <iostream>
#include <cstring>using namespace std;
const int N=150005;//开的3倍的数组
int fa[N];//其中1~n表示A种族,n+1~2n表示B种族,2n+1~3n表示C种族。(默认A吃B,B吃C,C是B)
int n,k,d,x,y,cnt;void init()
{for(int i=0;i<=3*n;i++){fa[i]=i;}
}int find(int x)
{if(fa[x]==x) return x;else{fa[x]=find(fa[x]);return fa[x];}
}void merge(int a,int b)//保证a,b为同一个集合(种族)
{if(find(a)==find(b)) return;fa[find(b)]=find(a);
}int main()
{scanf ("%d %d", &n, &k);init();for(int i=0;i<k;i++){scanf ("%d %d %d", &d, &x, &y);//此时的x和y同为A种族,因为x,y是在1~n的范围中if(x>n||y>n)//当前的话中x或y比n大,就是假话;{cnt++;continue;}if(d==1)//表示x,y为一个种族{if(find(x)==find(y+n)||find(x)==find(y+2*n))//如果当y是B种族,或者y是C种族,那么A,B必定不为同一种族,就是假话{cnt++;continue;}else//如果x与y是同一种族,那么由于当初输入的x,y是在1~n的范围中的,x,y其实可能是B种群或者C种族,所以确保x,y可以A,B,C为任一个种族{merge(x,y);//x,y是A种族merge(x+n,y+n);//x,y是B种族merge(x+2*n,y+2*n);//x,y是C种族}}else//表示x吃y{if(find(x)==find(y)||find(x)==find(y+2*n))//如果x,y为一个种族或者y吃x,就是假话{cnt++;continue;}else{merge(x,y+n);//x是A种族,y是B种族merge(x+n,y+2*n);//x是B种族,y是C种族merge(x+2*n,y);//x是C种族,y是A种族}}}cout << cnt << endl;return 0;
}