您的位置:首页 > 其它

poj1182食物链(种类,带权并查集)

2018-03-28 00:49 344 查看
题目大意:有三类不同动物,给出给K句话,描述两个动物间是同类还是捕食关系,若与前面的真话冲突,则判定为假话,输出假话的数量

思路分析:可用并查集将出现已知关系的动物合并在一起,各个动物到根结点距离对3的不同余数表示不同的种类,如对3的余数为0,1,2分别表示不同种的动物。当要将两物种合并在一起时,可通过修改其中一个跟结点的权值使这两种动物满足关系

#include<iostream>
#include<stdio.h>
using namespace std;
int p[100000],A[100000],n;
int f(int x){
if(x==p[x]) return x; int F=f(p[x]); //路径压缩,同时更新该结点的权值,这条语句不可以和下面的更改顺序,要先更新其原父节点的值(初始化时为0)才能更新其值。因为下面每次更新时只更新了一个集合根结点的值,但集合中其他元素的值未变,所以查询一个点的权值,可从父节点一步步更新
A[x]=(A[p[x]]+A[x])%3;
p[x]=F;
return F;
}
int u(int x,int a,int b){
int f1=f(a),f2=f(b);
if(a>n||b>n) return 0;
if(x==1){
if(f1==f2&&A[a]!=A[b]) return 0;
if(f1!=f2){ //当a和b不在同一个集合时,合并集合,同时修改a根结点f1的值,使合并后满足a和b同类
A[f1]=(A[b]-A[a]+3)%3;
p[f1]=f2;
}
}
else{
if(f1==f2){
if(A[a]==0&&A[b]!=1) return 0;
if(A[a]==1&&A[b]!=2) return 0;
if(A[a]==2&&A[b]!=0) return 0;
}
else{ //修改f1,使修改后满足a吃b,
A[f1]=(A[b]-A[a]+2)%3;
p[f1]=f2;
}
}
return 1;
}
int main(){
int a,b,c,m,i,sum=0;
scanf("%d%d",&n,&m);
for(i=0;i<=60000;i++){ //初始化并查集,同时使所有的点初始为0
A[i]=0;
p[i]=i;
}
for(i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
if(u(a,b,c)==0) sum++;
}
printf("%d\n",sum);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: