食物链------种类并查集

来源:互联网 发布:天津日报大厦知乎 编辑:程序博客网 时间:2024/06/05 17:41

原题传送门 :http://poj.org/problem?id=1182



推荐blog传送门,超级详细:http://blog.csdn.net/c0de4fun/article/details/7318642/



这种题,渣渣我是刚不了的……,百度了一堆帖子,说实话谈到关键代码的真的不是很多,也确实有好的帖子,让我收获了不少。

做题思路:

种类并查集,首先利用一个数组a来确定并查集关系,同时在建立一个数组b来表示某点与他们的boss点(根点)的关系。

现规定:

0: 某点与他的根点为同类

1: 某点与他的根点的关系为, 根点种类的动物的可以吃掉该点种类的动物

2: 某点与他的根点的关系为, 该点种类的动物的可以吃掉根点种类的动物

至于 那两个重要公式(代码已标注),如果自己不想推就去看推荐的那个blog,很详细。



几点注意:

1.如果两点没有并查集关系,首先给他们确定并查集关系

2. 如果两点有了并查集关系,检验他们所陈述的与根点的关系是否相同

3. 注意 输入的数据大于n的时候 不要让他们进入mergy函数



代码如下

#include <iostream>#include<cstdio>#include<cstring>#include <algorithm>using namespace std;int ans;int a[50100];int b[50100];void Init ()//初始化两个数组{    for(int i=1; i<=50100; i++)    {        a[i]=i;        b[i]=0;    }}int get_boss(int x){    if(a[x]==x) return x;    else    {        int t=a[x];        a[x]=get_boss(a[x]);        b[x]=(b[x]+b[t])%3;//带权并查集式,重要公式1        return a[x];    }}void mergy(int z,int x, int y){    int t1=get_boss(x);    int t2=get_boss(y);    if(z==1)    {        if(t1==t2)        {            if(b[x] != b[y])//false                ans++;        }        else        {            a[t2]=t1;            b[t2] = (b[x]-b[y]+3+(z-1))%3;//重要公式2, 另外+3的原因式剪发可能出现负数,因为模3,,3无所谓        }    }    else    {        if(t1==t2)        {            if( (b[x]+1) %3 !=b[y] ) // false // 下述推导            //(b[x]==0 && b[y]==1) || (b[x]==1 && b[y]==2) || (b[x]==2 && b[y]==0),除了这三种都是错的语句             ans++;        }        else        {            a[t2]=t1;            b[t2] = (b[x]-b[y]+3+(z-1))%3;        }    }}int main (){    int n,m,x,y,z;    scanf("%d %d",&n,&m);    Init();    ans=0;    while(m--)    {        scanf("%d %d %d",&z,&x,&y);        if(x>n|| y>n) ans++; //false        else if(x==y && z==2) ans++; // false        else  mergy(z,x,y);// n<x, n<y 千万不要让他们进来,错了N遍     }    printf("%d\n",ans);    return 0;}



原创粉丝点击