poj1182 食物链

题目链接:http://poj.org/problem?id=1182
题目解析:并查集变种。3种动物,形成循环的吃与被吃关系,动物之间共有三种关系,(2 X Y)X吃Y,Y被X吃。(1 X Y)X和Y同类,那么我们可以将这三种关系用数字0(同类),1(吃),2(被吃)表示。一个种类标记数组kind[],初始化全部为零,一个父节点数组parent[],记录当前节点的父节点,初始时为自己。初始化后,那么两个数组和在一起就表示当前节点与自己时同类。初始化时各个动物各成一颗树,我们可以通过不断将树合并,记录当前节点和根节点的关系,然后对比两个节点与根结点的关系,判断是否成立。
例: 若有三个动物,1,2,3。数组parent[]记录的值为 1 1 1 那么表示2和3是1的儿子节点,数组kind[]记录的值为 0 2 2;那么由根节点关系我们就可以判断出2和3是同类,依次类推。注意当kind[]是与parent[]相对应的。
#include<stdio.h>
#define MAX 50010
int parent[MAX],kind[MAX];  //kind[] 0表示同类,2表示被吃,1表示吃
int n,k,cnt;
void UFset()
{
     int i;
     for (i=1;i<=n;i++)
     {
         parent[i]=i;
         kind[i]=0;
     }     
}
int find(int x,int &m)
{
    int s=x;
    m=kind[x];
    while (x!=parent[x])
    {
       int t=parent[x];
       if (t!=parent[t])     //往根移动,记录当前节点与祖先节点的关系。
          m=(m+kind[parent[x]])%3;
       x=parent[x];   
    }
    parent[s]=x; //状态压缩,将查询的节点直接接在祖先节点之后
    kind[s]=m;   //因为当前查询的节点父节点已变,所以得更新他与当前父节点的关系。
    return x;
}
int check(int w,int u,int v)
{
    int i,j,ux,uy,x,y;
    x=find(u,ux);
    y=find(v,uy);
    if (w==1)
    {
       if (x!=y)
       {
          parent[y]=x;
          if (ux==uy)
          {
             kind[y]=0;
          }
          else if (ux==1&&uy==2)
          {
             kind[y]=2;              
          }
          else if (ux==0)
          {
             kind[y]=3-uy;     
          }
          else if (uy==0)
          {
             kind[y]=ux;  
          }
          else
          {
             kind[y]=1;    
          }      
          return 1;  
       }  
       else if (ux==uy)
       {  
            return 1;
       }       
       else
       {
          return 0;     
       }
    }
    else
    {
       if (x!=y)
       {
          parent[y]=x;
          if (uy==0)  
          {  
             kind[y]=(ux-1)<0?2:(ux-1);  
          }  
          else if(uy==1&&ux==0)  
                kind[y]=1;  
          else if(uy==1&&ux==1)  
                kind[y]=2;  
          else if(uy==1&&ux==2)  
                kind[y]=0;  
          else if(uy==2)  
                kind[y]=ux;  
          return 1; 
       } 
       else if ((uy==1&&ux==2)||(uy==0&&ux==1)||(uy==2&&ux==0))
       {   
           return 1;
       }       
       else
       {
          return 0;     
       }
    }
}
int main()
{
    //while (1){
    int i,j,u,v,w;
    cnt=0;
    scanf("%d%d",&n,&k);
    UFset();
    for (i=0;i<k;i++)
    {
        scanf("%d%d%d",&w,&u,&v);    
        if (u>n||v>n||(w==2&&u==v))
        {
           cnt++;
           continue;                           
        }
        if (!check(w,u,v))
        {
             cnt++;
             //printf("%d  %d  %d\n",w,u,v);
        }
    }
    printf("%d\n",cnt);
    //}
    return 0;    
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值