Description
现有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
以下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和b是同类关系,那就把a和b划分到一个集合中,之后再说a和b是捕食关系一定是假话了。但是这道题的问题在于某一个动物在食物链中的角色不是一定的,一个物种可能作为捕食者也可能是被捕食者,还有可能给出同类之间的关系,那该怎么办呢?将所扮演的三种状态全都表示出来。列如,对于物种x,x代表A类,x+n代表B类,x+2n代表c类,其中A吃B,B吃C,C吃A。
对于两个动物如果是同类关系,那么一定不存在捕食和被捕食关系;如果存在捕食关系,那么一定不存在被捕食和同类关系。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define MAX 50010*3 5 using namespace std; 6 int pre[MAX]; 7 int Find(int x) 8 { 9 int a; 10 a=x; 11 while(pre[a]!=a) 12 { 13 a=pre[a]; 14 } 15 return a; 16 } 17 void Union(int root1,int root2) 18 { 19 int x,y; 20 x=Find(root1); 21 y=Find(root2); 22 if(x!=y) 23 { 24 pre[x]=y; 25 } 26 } 27 int Same(int x,int y)///判断两个物种是否有关系 28 { 29 return Find(x)==Find(y); 30 } 31 int main() 32 { 33 int n,m,i,counts; 34 int a,b,q; 35 scanf("%d%d",&n,&m); 36 counts=0; 37 for(i=1;i<=n*3;i++)///开三倍的数组 38 { 39 pre[i]=i; 40 } 41 for(i=1;i<=m;i++) 42 { 43 scanf("%d%d%d",&q,&a,&b); 44 if(a<1||a>n||b<1||b>n)///输入的数不合法为假话 45 { 46 counts++; 47 continue; 48 } 49 if(q==1) 50 { 51 if(Same(a,b+n)||Same(a,b+2*n))///存在捕食关系或者被捕食关系 52 { 53 counts++; 54 } 55 else///建立同类关系 56 { 57 Union(a,b); 58 Union(a+n,b+n); 59 Union(a+2*n,b+2*n); 60 } 61 } 62 else if(q==2) 63 { 64 if(Same(a,b)||Same(a,b+2*n))///存在同类或者被捕食关系 65 { 66 counts++; 67 } 68 else///建立所有的捕食关系 69 { 70 Union(a,b+n); 71 Union(a+n,b+2*n); 72 Union(a+2*n,b); 73 } 74 } 75 } 76 printf("%d\n",counts); 77 return 0; 78 }