[题解] POJ 1182 食物链 (并查集)

来源:互联网 发布:无损音乐检测软件 编辑:程序博客网 时间:2024/06/05 07:05

  题意: 有A,B,C三种类型的动物,他们之间的关系为:A吃B,B吃C,C吃A。现给出k条信息,第一种:X和Y是同类,第二种:X吃Y。若某一条信息与前面信息相矛盾(或者明显错误),则它在说谎,问说谎的信息总数是多少
  分析: 由于我们无法方便的确定哪个动物属于A,B,C类(其实他们是等价的),所以我们就能通过分析他们与同一个动物的关系来确定任意两动物相互间的关系。而且,经过分析你会发现关系是可以传递的!X吃Y,Y吃Z,则Z必然吃X。利用传递性,我们就可以将所有动物链接起来,形成一棵带边权树(森林)。具体操作通过并查集实现即可。
  对于每对节点,可能有三种关系:X和Y同类,X吃Y,Y吃X。我们可以分别用边权 0、1、2 来表示三种关系。并且关系的传递我们可以直接通过相加来确定!如:X->Y=1 Y->Z=2 则 X->Z=(1+2)%3=0!
  当进行1操作时,我们直接将X的祖先与Y的祖先链接起来,并且使得这条边等价于在X,Y间连一条边权为0的单向边
  当进行2操作时,我们直接将X的祖先与Y的祖先链接起来,并且使得这条边等价于在X,Y间连一条边权为1的单向边
  得知了这个关系,我们就可以愉快的虐题了!
  详细代码如下:

#include <bits/stdc++.h>using namespace std;int n,k,ans=0;int fa[50010],f[50010];int read() {    int ans=0,flag=1;    char ch=getchar();    while((ch>'9' || ch<'0') && ch!='-') ch=getchar();    if(ch=='-') flag=-1,ch=getchar();    while(ch>='0' && ch<='9') ans=ans*10+ch-'0',ch=getchar();    return ans*flag;}//1为吃,2为被吃,0为同类 f[x]=1 fa[x]=y说明xyint find(int x) {     if(fa[x]!=x) {        int temp=fa[x];        fa[x]=find(fa[x]);        f[x]=(f[x]+f[temp])%3;     }     return fa[x];}               void merge(int x,int y,int work) {    f[x]=work;    fa[x]=y;}int main() {    n=read();k=read();    for(int i=1;i<=n;i++) {fa[i]=i;}    for(int i=1;i<=k;i++) {        int a,x,y,fx,fy;        a=read(),x=read(),y=read();        if(x>n || y>n) {            ans++;            continue;        }        fx=find(x),fy=find(y);        if(a==1) {            if(fx==fy) {//矛盾                if((f[x]-f[y]+3)%3!=0) {                    ans++;                }            }else {                merge(fx,fy,(f[y]-f[x]+3)%3);            }        }else {            if(fx==fy) {//矛盾                if((f[x]-f[y]+3)%3!=1) {                    ans++;                }            }else {                merge(fx,fy,(1+f[y]-f[x]+3)%3);            }        }    }    printf("%d\n",ans);    return 0;}

                                     by:Chlience

原创粉丝点击