• 并查集:CDOJ1594-老司机的奇幻漂流 (食物链)


    老司机的奇幻漂流 UESTC - 1594

    Problem Description

    老司机在救出了女票之后,就和她在全世界旅游,有一天,他们来到了一个神奇的小岛上。
    这个小岛上有三种动物,他们互相克制,就像虚空追猎凤凰石头剪刀布一样,他们形成了一个食物环。
    热爱小动物的老司机女票已经对这个岛上的N只动物进行了细致的研究,对他们所属的族群也了如指掌,并对他们的行为做了记录。
    第一种记录方式是1 X Y,表示X和Y关系密切(是同类)。
    第二种记录方式是2 X Y,表示X对Y有攻击性行为(X克制Y)。
    不过很不凑巧,这些记录被毛手毛脚的JJ给打乱了,使得其中一些记录出现了错误。
    为了安慰着急的女票,老司机急忙来帮忙查看是哪些记录出现了错误,当一条记录满足以下三种可能之一时,这就是一条错误的记录。
    1)这条记录中的X或者Y比N大
    2)攻击性记录中的X攻击了X
    3)这条记录与前面的记录相悖
    老司机说是来帮忙,但是还要忙着跑去和wyy踢fifa,所以就让你来完成这个任务,找出这些记录中哪些错了。
    Input
    第一行两个整数N和M,为记录的动物数量和记录条数
    接下来M行,每行代表一条记录。

    Output

    一行n个数字,表示哪几条记录有误,用空格隔开
    按编号升序输出

    Sample Input

    100 7
    1 101 1
    2 1 2
    2 2 3
    2 3 3
    1 1 3
    2 3 1
    1 5 5

    Sample Output

    1 4 5
    Hint

    数据范围:

    1<= N <= 50,000
    1<= M <=100,000


    1. 这是一个食物链问题的并查集,算是并查集中比较高端的问题了,这里有一个很好的博客,想了解的可以去看看食物链并查集,其实在看了这个博客之后还不是很懂,但是模板大概是个什么样子还是知道了。这里面有一个很核心的公式:rootx->rooty = (relation[x]+d-1+3-relation[y])%3 = relation[rooty]

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 1e5+100;
    struct node
    {
        int pre;
        int relation;
    } p[maxn];
    
    int find(int x)
    {
        int temp;
        if(x == p[x].pre)
            return x;
        temp = p[x].pre;
        p[x].pre = find(temp);
        p[x].relation = (p[x].relation + p[temp].relation)%3;
        return p[x].pre;
    }
    
    int main()
    {
        int n,m;
        while(cin>>n>>m)
        {
            queue <int> qu;
            for(int i=1; i<=n; i++)
            {
                p[i].pre = i;
                p[i].relation = 0;
            }
            for(int i=1; i<=m; i++)
            {
                int a,b,c;
                cin>>c>>a>>b;
                if(a == b && c == 2)
                {
                    qu.push(i);
                    continue;
                }
                if(a > n || b > n)
                {
                    qu.push(i);
                    continue;
                }
                int fa = find(a);
                int fb = find(b);
                if(fa != fb)
                {
                    p[fb].pre = fa;
                    p[fb].relation = (3 + (c - 1) + p[a].relation - p[b].relation)%3;//很重要的合并公式
                    //rootx->rooty = (relation[x]+d-1+3-relation[y])%3 = relation[rooty](公式)
                }
                else
                {
                    if(c == 1 && p[a].relation != p[b].relation)//同类但是和父类的关系不同是不可能的
                        qu.push(i);
                    if(c == 2 && ((3 - p[a].relation + p[b].relation)%3 != c -1))//检验是否是符合捕食关系
                        qu.push(i);
                }
            }
            if(qu.empty())
                continue;
            printf("%d",qu.front());
            qu.pop();
            while(!qu.empty())
            {
                printf(" %d",qu.front());
                qu.pop();
            }
        }
        return 0;
    }
    
    
    
  • 相关阅读:
    Socket接口(基于 Linux-2.4.0已更新)
    IP协议源码分析(基于linux-2.4.0已更新)
    udp_sendmsg源码完整分析(基于linux5.12.13版本内核)
    UDP详细理解(实现部分基于linux5.12.12版本内核)
    IP地址分配(静态分配+动态分配+零配置)
    计算机网络由哪些硬件设备组成?(基础收录)
    浅析C语言定义时赋值、定义后赋值、定义时不赋值
    《C指针全解》让你不再害怕指针
    makdown文字图片居中字体颜色表格列宽
    (C语言内存二十一)C语言变量的存储类别和生存期
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9107294.html
Copyright © 2020-2023  润新知