POJ1182-食物链,POJ1703-Find them, Catch them 题解

如果只是用普通的并查集,表示两个动物是同类的时候还比较容易,但是对于x吃y这种情况就有点困难。因为并查集是把同类归到一起,对于不同类的处理就没那么容易了,那么我们不妨思考怎么把x吃y的这种情况转化成类似a和b是同类的情况?

思路:
x和y虽然不是同类,但是x吃的类和y是同类,y吃的类和吃x的类也是同类,那么我们就可以将x加上n 表示被x吃的类 x加上2n表示吃x的类,对于y同样处理。那么对于x吃y这种关系我们就可以这么表示:f[x+n]=f[y] f[x+2n] = f[y+n] f[x]=f[y+2n]

注意:本题的输入数据比较大,即使用取消同步的cin也会超时,必须用scanf输入

//poj1182
#include <cstdio>
const int N = 5e4 + 5;
using namespace std;

int f[N * 3]; // x+n表示被x吃的类,x+2*n表示吃x的类
int Find(int x) { return f[x] == x ? x : f[x] = Find(f[x]); }

int main()
{
    int cnt = 0;
    int n, m, op, x, y, fx[3], fy[3];
    scanf("%d%d", &n, &m);
    getchar();
    for (int i = 3 * n; i > 0; i--)
        f[i] = i;
    while (m--)
    {
        scanf("%d%d%d", &op, &x, &y);
        getchar();
        if (x > n || y > n)
            cnt++;
        else
        {
            for (int i = 0; i < 3; i++)
            {
                fx[i] = Find(x + n * i);
                fy[i] = Find(y + n * i);
            }
            if (op == 1)
            {
                // x吃y 或 y吃x
                if (fx[1] == fy[0] || fy[1] == fx[0])
                    cnt++;
                else
                {
                    for (int i = 0; i < 3; i++)
                        f[fx[i]] = fy[i];
                }
            }
            else
            {
                // y吃x 或 x和y相同
                if (fy[1] == fx[0] || fx[0] == fy[0])
                    cnt++;
                else
                {
                    f[fx[0]] = f[fy[2]];
                    f[fx[1]] = f[fy[0]];
                    f[fx[2]] = f[fy[1]];
                }
            }
        }
    }
    printf("%d", cnt);
    return 0;
}

poj1703的做法与上题相同,并且只有两个状态,更容易一些

//poj1703
#include <cstdio>
const int N = 1e5 + 5;
using namespace std;

int f[2 * N], sz[2 * N]; //x+n表示与x不同的帮派
int Find(int x) { return f[x] == x ? x : f[x] = Find(f[x]); }
int main()
{
    int t;
    scanf("%d", &t);
    getchar();
    while (t--)
    {
        char op;
        int a, b, n, m;
        scanf("%d %d", &n, &m);
        getchar();
        for (int i = 2 * n; i >= 0; i--)
        {
            f[i] = i;
            sz[i] = 1;
        }
        while (m--)
        {
            scanf("%c %d %d", &op, &a, &b);
            getchar();
            int fa, fb, fan, fbn;
            fa = Find(a);
            fb = Find(b);
            fan = Find(a + n);
            fbn = Find(b + n);
            if (op == 'A')
            {
                if (fa == fb || fan == fbn)
                    printf("In the same gang.\n");
                else if (fa == fbn || fan == fbn)
                    printf("In different gangs.\n");
                else
                    printf("Not sure yet.\n");
            }
            else
            {
                if (sz[fa] > sz[fbn])
                {
                    f[fbn] = f[fa];
                    sz[fa] += sz[fbn];
                }
                else
                {
                    f[fa] = f[fbn];
                    sz[fbn] += sz[fa];
                }
                if (sz[fan] > sz[fb])
                {
                    f[fb] = f[fan];
                    sz[fan] += sz[fb];
                }
                else
                {
                    f[fan] = f[fb];
                    sz[fb] += sz[fan];
                }
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值