链接:点击打开链接
题意:有N只动物,分别编号为1~N,所有动物都属于A,B,C中其中一种,已知A吃B,B吃C,C吃A。按顺序给出下面的两种信息共K条。第一种:x和y属于同一种,第二种:x吃y。然而这些信息有可能会出错,有可能有的信息和之前给出的信息矛盾,也有的信息可能给出的x,y不在范围内,求矛盾的信息有多少条
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
int n,k,ans;
int father[150005],depth[150005],t[150005],x[150005],y[150005];
int found(int x){
if(father[x]!=x)
father[x]=found(father[x]);
return father[x];
}
void unite(int x,int y){
x=found(x);
y=found(y);
if(x==y)
return;
if(depth[x]<depth[y])
father[x]=y;
else{
father[y]=x;
if(depth[x]==depth[y])
depth[x]++; //加了一个数组存树的深度以此优化
}
}
bool same(int x,int y){
return found(x)==found(y);
} //白书上的并查集模板
int main(){
int i,j;
scanf("%d%d",&n,&k);
ans=0;
for(i=0;i<3*n;i++){
father[i]=i;
depth[i]=0;
}
for(i=0;i<k;i++){
scanf("%d%d%d",&t[i],&x[i],&y[i]);
x[i]--;y[i]--; //把3*N分成三部分分别代表A,B,C,因为我们输入一组数据时
if(x[i]<0||x[i]>=n||y[i]<0||y[i]>=n){ //只知道相互的逻辑关系是什么,并不知道分别代表的是什么
ans++; //因此我们所有的可能都看做元素,然后通过并查集判断之间
continue; //的关系
}
if(t[i]==1){
if(same(x[i],y[i]+n)||same(x[i],y[i]+2*n))
ans++; //不同类时计数
else{
unite(x[i],y[i]); //将所有符合情况的可能放入集合中
unite(x[i]+n,y[i]+n);
unite(x[i]+2*n,y[i]+2*n);
}
}
else{
if(same(x[i],y[i])||same(x[i],y[i]+2*n))
ans++;
else{
unite(x[i],y[i]+n);
unite(x[i]+n,y[i]+2*n);
unite(x[i]+2*n,y[i]);
}
}
}
printf("%d\n",ans);
return 0;
}