poj1182

链接:点击打开链接

题意:有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;
}

你可能感兴趣的:(poj1182)