poj 1182 食物链(并查集)

很典型的并查集,我们只需要找到A,B,C类,然后我们必须保存他们之间的关系,这个关系我们使用3进制表示,同类(0),吃(2),被吃(2).然后我们就有一定的变换关系了。
rank[]//用来表示他与父节点的关系。
1 x y(x,y同类),x所在集合的根节点a,y所在的根节点b.(a!=b)
rank[x](x->a)==rank[y](y-->a)
rank[a](a->b)=rank[y](y->b)-rank[x](x->a);传递性
2 x y(x eat y)
rank[y](y->a)=rank[y](y->x)+rank[x](x->a),rank[y](y->x)=2;
so
  rank[y](y->a)=2+rank[x](x->a);式1

rank[a](a->b)=rank[y](y->b)-rank[y](y->a);传递性  式2
由式1,2得
rank[a](a->b)=rank[y](y->b)-2-rank[x](x->a);

代码:

 #include<stdio.h>
#define maxN 50001
struct{
  int pre;
  int rank;
  }animal[maxN];
void init(int i)
{
 animal[i].pre=-1;
 animal[i].rank=0;//i节点与父节点的关系。0表示同类,2表示被吃,1表示吃。
}
int find(int i)
{
 int t=animal[i].pre;
 if(t<0)
  return i;
 animal[i].pre=find(t);
 animal[i].rank=(animal[i].rank+animal[t].rank)%3;//路径压缩

 return animal[i].pre;

}

int main()
{
 int n,k,i,d,x,y;
 int lie=0;
 scanf("%d%d",&n,&k);
 for(i=1;i<=n;i++)
  init(i);
 for(i=0;i<k;i++)
 {
  scanf("%d%d%d",&d,&x,&y);
  if((x>n||y>n)||(d==2&&x==y))
   {
    lie++;
    continue;
   }
  int a=find(x);
  int b=find(y);
  if(d==1)//x,y同类
  {
   if(a==b)//如果x,y在一个集合.
    
    {
     if(animal[x].rank!=animal[y].rank)//如果x,y与根节点的关系不同,则表示x,y不在一个集合
      lie++;
    }
   else//不在一个集合
   {
    animal[a].pre=b;//y所在的集合与x所在的集合合并,且根为b

    animal[a].rank=(animal[y].rank-animal[x].rank+3)%3;//由于传递性
   }
  }
  if(d==2)
  {
   if(a==b)
   {
    if(animal[x].rank!=(animal[y].rank+1)%3)//由于传递性
     lie++;

   }
   else
    {
     animal[a].pre=b;
     animal[a].rank=(animal[y].rank-animal[x].rank+4)%3;//传递性
    }
  }
 }
printf("%d/n",lie);
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值