【NOI2001】【洛谷P2024】食物链
问题描述
输入格式
输出格式
样例输入
100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1
1 5 5
样例输出
3
数据范围
题解
动物王国的动物分为三个集合A,B,C,其中A吃B,B吃C,C吃A。我们用并查集表示这些集合间的关系
对于两个动物x,y,它们之间存在3种关系,即x,y是同类,x吃y,或y吃x
我们不知道两个动物是A,B,C中的哪两种,但是我们知道它们之间的关系一定在以上3种关系之间
对于一个动物x,不妨设x+n表示吃x的动物所在的集合,x+n*2表示被x吃的动物所在的集合
对于每一句话,若存在动物的编号大于n,显然这句话是假的
我们先讨论集合的合并
若x和y是同类,那么吃x的动物和吃y的动物在同一个集合,被x吃的动物和被y吃的动物在同一个集合;即将x和y所在集合合并,将x+n和y+n所在集合合并,将x+n*2和y+n*2所在集合合并
若x吃y,则x和吃y的动物在同一个集合,y和被x吃的动物在同一个集合,即将x和y+n所在集合合并,将y和x+n*2所在集合合并。由题干描述的3种动物的捕食关系可知,还存在一个和x,y都不属于同一个集合的z,满足y吃z且z吃x。那么z所在集合应和y+n*2所在集合合并,且和x+n所在集合合并,我们可以把y+n*2和x+n所在集合合并即表示z所在集合。
接下来我们讨论判断一句话的真假
若是第一种说法,若这句话为真,则在已知的关系中必不存在x吃y,或y吃x,或x吃z,z吃y,或y吃z,z吃x,否则这句话为假。
若是第二种说法,若这句话为真,则已知关系中必不存在x和y属于同一类,并且吃x的动物和吃y的动物不属于同一类,被x吃的动物和被y吃的动物不属于同一类(因为任意两个动物如果不是同类则只存在两种关系,即直接的吃与被吃,所以若吃两个动物的动物属于同一类,则这两个动物必属于同一类,被两个动物吃的动物亦然),否则这句话为假
1 #include <cstdio> 2 int n,m,f[150005],ans; 3 int find(int x) 4 { 5 if (f[x]==x) return x; 6 return f[x]=find(f[x]); 7 } 8 int main() 9 { 10 int i,j,p,x,y,fx,fy,fx1,fy1,fx2,fy2; 11 // x+n 捕食者 12 // x+n*2 被捕食者 13 scanf("%d%d",&n,&m); 14 for (i=1;i<=n*3;i++) 15 f[i]=i; 16 while (m--) 17 { 18 scanf("%d%d%d",&p,&x,&y); 19 if (x>n || y>n) 20 { 21 ans++; 22 continue; 23 } 24 fx=find(x); fy=find(y); 25 fx1=find(x+n); fy1=find(y+n); 26 fx2=find(x+n*2); fy2=find(y+n*2); 27 if (p==1) 28 { 29 if (fx1==fy || fx2==fy || fx1==fy2 || fx2==fy1) 30 { 31 ans++; 32 continue; 33 } 34 f[fx]=fy; f[fx1]=fy1; f[fx2]=fy2; 35 } 36 else 37 { 38 if (fx1==fy1 || fx1==fy || fx2==fy1) 39 { 40 ans++; 41 continue; 42 } 43 f[fx]=fy1; f[fx1]=fy2; f[fx2]=fy; 44 } 45 } 46 printf("%d",ans); 47 return 0; 48 }