食物链 POJ - 1182-(扩展域并查集)

维护具有多重关系的集合(扩展域)

总结

首先这个题AC了部分,让我很难受在这里插入图片描述
用了四个OJ测试,就SCU过不了,我就不知道为什么,是我的程序有BUG,还是他的数据有问题,如果我的代码有问题,极力欢迎纠正。

这个题好像有两个写法,一个是本题的写法,一个边带权写法。

解析

fat[N*3],这里会开辟三个域,一个指自己本身,一个作为天敌状态,一个作为食物状态。
然后就是模拟完事吧。

补充

之前我一直有一个迷惑,一棵树里的关系到底维护什么?
每一个结点都有三个状态,也是我们创建的三个域

以前的想法
[1,n]一定为自己
[n+1,2n]一定为食物
[2
n+1,3*n]一定为天敌

后来的想法
一棵树中数据[1,n]的所有数字同类,暂且为a类,数据[n+1,2n]的所有数字为同类,暂且为b类,数据[2n+1,3*n]的所有数字为同类,暂且为c类,然后关系一定满足a吃b吃c吃a,维护的就是这个关系。

关系再准确一点就是
情况一
Xa吃Yb吃Zc吃Xa

情况二
Xb吃Yc吃Za吃Xb

情况三
Xc吃Ya吃Zb吃Xc

每次合并三种类型,也就维护了三种状态了。

每一颗树中,某一个集合中a类,b类,c类就很明显看到动物X与动物Y之间存在什么关系!
如果X与Y关系在某一个集合与之前的关系不矛盾,那就建立关系(任意一个集合都能看出关系,一定的
如果矛盾,那就ans++

const int N=5e4+5;
int fat[N*3];
int find(int x)
{
    return fat[x]==x?x:fat[x]=find(fat[x]);
}
signed main()
{
    IOS;
    file();
    int n,m,ans=0;
    cin>>n>>m;
    for(int i=1;i<=n*3;i++)
        fat[i]=i;
    while(m--)
    {
        int flag,a,b;
        cin>>flag>>a>>b;
        if(a>n||b>n)
        {
            ans++;
            continue;
        }
        ///a1吃a2吃a3吃a1
        int a1=find(a),a2=find(a+n),a3=find(a+2*n);
        int b1=find(b),b2=find(b+n),b3=find(b+2*n);
        if(flag==1)
        {
            if(a1==b2||b1==a2)///判断a和b是否具有捕食关系
                ans++;
            else
            {
                fat[a1]=b1;
                fat[a2]=b2;
                fat[a3]=b3;
            }
        }
        else
        {
            if(a1!=b1&&b1!=a2)///判断a和b不是同类且b不吃a
            {
                fat[a1]=b2;
                fat[a2]=b3;
                fat[a3]=b1;
            }
            else
                ans++;
        }
    }
    cout<<ans<<endl;
    return 0;
}
发布了130 篇原创文章 · 获赞 5 · 访问量 4991

猜你喜欢

转载自blog.csdn.net/weixin_44224825/article/details/104256773