洛谷2024 食物链
题目描述
动物王国中有三类动物 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 句话有的是真
的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。
• 当前的话与前面的某些真的话冲突,就是假话
• 当前的话中 X 或 Y 比 N 大,就是假话
• 当前的话表示 X 吃 X,就是假话
你的任务是根据给定的 N 和 K 句话,输出假话的总数。
输入输出格式
输入格式:
从 eat.in 中输入数据
第一行两个整数,N,K,表示有 N 个动物,K 句话。
第二行开始每行一句话(按照题目要求,见样例)
输出格式:
输出到 eat.out 中
一行,一个整数,表示假话的总数。
输入输出样例
100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5
3
说明
1 ≤ N ≤ 5 ∗ 10^4
1 ≤ K ≤ 10^5
解题思路:
1.弱智错误
先排除弱智错误
p==2&&x==y
x>n||y>n
2.分类讨论
p==1时。。。。。。
p==2时。。。。。。
用0表示同类
用1表示A吃B
用2表示A被b吃
重点:
看图
代码如下(两种方法)
方法1(世杰比特牛版)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 using namespace std; 5 int find(int); 6 void unionn(int,int); 7 int n,k,x,y,father[50005],p,dis[50005],cnt=0,f; 8 int main() 9 { 10 //0 同类 11 //1 A吃B 12 //2 C被A吃 13 freopen("2024.txt","r",stdin); 14 scanf("%d %d",&n,&k); 15 for(int i=1;i<=n;i++) 16 father[i]=i; 17 memset(dis,0,sizeof(dis)); 18 for(int i=1;i<=k;i++) 19 { 20 scanf("%d%d%d",&p,&x,&y); 21 if(x>n||y>n) 22 {cnt++; 23 continue;} 24 if(x==y&&p==2) 25 {cnt++; 26 continue;} 27 else 28 {int r1=find(x); 29 int r2=find(y); 30 if(r1!=r2) 31 {int t=dis[y]; 32 unionn(r1,r2); 33 dis[r2]=(dis[x]-t+p-1+3)%3; 34 } 35 else 36 37 if(x!=y) 38 {f=(3+dis[x]-dis[y])%3; 39 if(p==1&&f!=0) 40 { 41 cnt++; 42 continue; 43 } 44 if(p==2&&f!=2) 45 { 46 cnt++; 47 continue; 48 } 49 } 50 }} 51 printf("%d",cnt); 52 } 53 int find(int m) 54 { 55 if(father[m]!=m) 56 { 57 int kk=father[m]; 58 father[m]=find(father[m]); 59 dis[m]=(dis[m]+dis[kk])%3; 60 } 61 return father[m]; 62 } 63 void unionn(int r1,int r2) 64 { 65 father[r2]=r1; 66 }
方法2(自制版)
#include<cstdio> #include<cstring> #include<iostream> using namespace std; int find(int); void unionn(int,int); int n,k,x,y,father[50005],p,dis[50005],cnt=0,f; int main() { //0 同类 //1 A吃B //2 C被A吃 //freopen("2024.txt","r",stdin); scanf("%d %d",&n,&k); for(int i=1;i<=n;i++) father[i]=i; memset(dis,0,sizeof(dis)); for(int i=1;i<=k;i++) { scanf("%d%d%d",&p,&x,&y); if((x>n||y>n)||(x==y&&p==2)) {cnt++; continue;} if(p==1) { int r1=find(x); int r2=find(y); if(r1==r2) if(dis[x]!=dis[y]) { cnt++; continue; } dis[father[x]]=(dis[y]-dis[x]+6)%3; father[father[x]]=father[y]; } if(p==2) { int r1=find(x); int r2=find(y); if(r1==r2) if(dis[x]!=(dis[y]+1)%3) { cnt++; continue; } dis[father[x]]=(dis[y]-dis[x]+4)%3; father[father[x]]=father[y]; } } printf("%d",cnt); } int find(int x) { if(x!=father[x]) { int xx=father[x]; father[x]=find(father[x]); dis[x]=(dis[x]+dis[xx])%3; } return father[x]; } void unionn(int r1,int r2) { father[r2]=r1; }