zoukankan      html  css  js  c++  java
  • POJ 1182【食物链】(边带权/扩展域 并查集)

    题目链接 http://poj.org/problem?id=1182

    第一种 扩展域

    对于几个编号为x的动物  我们用x表示它的同类域,x+n表示它的捕食域,x+2*n表示它的天地域。

    我们用并查集来维护动物之间的关系,也即维护这三种域之间的关系

    当给定一个指令 1 x y 时,说明x和y是同类,什么情况下这个话是错误的呢,当

    x捕食y,或者y捕食x的时候这句话是错的,所以此时我们就查询 x与y+n  y与x+n是否有共同祖先

    1 如果有,说明它俩在同一个集合中,那它俩就不可能同类,这句话就是错误的

    2 如果没有,那么这句话就是对的,那么我们就合并 x与y,x+n与y+n,x+2*n与y+2*n,把它们并到一个集合中。

    当给定一个指令 2 x y时,说明x捕食y,什么情况下这个话是错误的呢,当x和y时同类,或者y捕食x,那么这句话就是错误的。

    此时我们就查询 x与y,x与y+n是否是否有共同祖先

    如果有,说明它俩在同一个集合中,这句话就是错误的

    如果没有,那么这句话就是对的,那么我们就合并 x+n与y,x与y+2*n,把它们并到一个集合中。

    注意食物链是一个环,x捕食y也说明了 y的捕食对象是x的天敌,因此此时我们再合并 y+n与x+2*n

    #include<bits/stdc++.h>
    using namespace std;
    const int M = 5e4 + 5;
    int fa[3 * M];
    int n, k,cnt; 
    int get(int x)
    {
        if (fa[x] == x) return x;
        return fa[x] = get(fa[x]);
    }
    bool same(int x, int y)
    {
        return get(x) == get(y); 
    }
    void merge(int x, int y)
    {
        fa[get(x)] = get(y);
    }
    int main(){
        cin >> n >> k;
        for (int i = 0; i <= 3 * n; i++)
        {
            fa[i] = i; // i表示同类域 i+n表示捕食域 i+2*n表示天敌域
        }
        while (k--)
        {
            int op, x, y;
            scanf("%d%d%d", &op, &x, &y);
            if (x > n || y > n || x < 1 || y < 1) {
                cnt++;
                continue;
            }
            if (op == 1)
            {
                if (same(x, y + n) || same(x + n, y) )
                    cnt++;
                else
                {
                    merge(x, y);
                    merge(x + n, y + n);
                    merge(x + 2 * n, y + 2 * n);
                }
            }
            else {
                if (same(x, y) || same(x, y + n))
                    cnt++;
                else
                {
                    merge(x + n, y);
                    merge(x, y + 2*n);
                    merge(x + 2 * n, y + n);
                }
            }
        }
        cout << cnt << endl;
        return 0;
    }
    扩展域

    第二种 边带权

    我们给编号为x的动物一个权值d[x] ,这个权值为它和节点之间的关系

    d[x]=0说明它和父节点同类,=1说明它捕食父节点,=2说明它被父节点捕食。

    我们在路径压缩的过程同时更新权值d[x],x的父节点之前是fa[x],压缩后父节点变成了根节点,所以父节点变了,权值也应当发生改变

    d[x]=(d[x]+d[fa[x]])%3

    对于给的指令 d x y,如果x和y有共同根节点,说明他们在一个集合,那从在这个集合中,x与y已经有了共同根节点,且深度都为1,x与y的关系可以表示为d[x]+d[fa[x]->y] 

    d[fa[x]->y]就是 3-d[y] ,所以x与y的关系可以表示为

    (d[x]+3-d[y])%3

    如果(d[x]+3-d[y])%3 != d-1,(d为1,表示x和y同类,那么d-1就是0,这里不矛盾,d为2也是一样) 既x和y不满足所给关系,那这句话就是错的

    如果x和y没有共同根节点,那么它俩的关系还不清楚,所以就合并它俩所在的集合,p和q分别表示x和y的根节点

    我们让fa[p]=q;

    此时我们更改了p的父节点,那它的权值d[p]也要发生相应改变,那这是一种怎样的传递关系呢?我们假设d[p]是我们要求的值,关系如下

    (d[x]+d[p](此时p的父节点已经为q,这里d[p]就是我们要求的)+d[q->y])%3=d-1
    d[q->y]=3-d[y](q是y的父节点)
    所以可以得到d[p] = (d[y] - d[x] + 3 + d - 1) % 3;

    这样就行啦。

    #include<bits/stdc++.h>
    using namespace std;
    const int M = 5e4 + 5;
    int fa[M], d[M]; //0表示与父节点同类 1表示吃父节点 2表示被吃
    int n, k, cnt;
    int get(int x)
    {
        if (fa[x] == x) return x;
        int root = get(fa[x]);
        d[x] = (d[x] + d[fa[x]]) % 3;
        return fa[x] = root;
    }
    void merge(int x, int y)
    {
        fa[get(x)] = get(y);
    }
    int main(){
        cin >> n >> k;
        for (int i = 0; i <= n; i++)
        {
            fa[i] = i; 
        }
        while (k--)
        {
            int op, x, y;
            scanf("%d%d%d", &op, &x, &y);
            if (x > n || y > n || x < 1 || y < 1) {
                cnt++;
                continue;
            }
            int p = get(x), q = get(y);
            if (p == q)
            {
                if ((d[x] + 3 - d[y]) % 3 != op - 1)
                    cnt++;
                continue;
            }
            fa[p] = q;
            d[p] = (d[y] - d[x] + 3 + op - 1) % 3;
        }
        cout << cnt;
        return 0;
    }
    边带权
  • 相关阅读:
    Ajax校验
    Struts2国际化
    OGNL
    Struts2基础数据校验和框架校验
    http
    AES,BigInteger,MD5加密
    随笔 js-----------------------------------------------------------------------------------------------------
    13年总结js,css,java xml
    window、linux安装jdk,excel 导入oracle,WebService,window 端口查看,svn服务安装,oracle用户解锁
    经典sql语句
  • 原文地址:https://www.cnblogs.com/xiaoguapi/p/10458812.html
Copyright © 2011-2022 走看看