poj 1703 Find them, Catch them(数据结构:并查集)

又是一道典型的并查集应用

社会上有两个黑帮

任给你2个人的编号,若前面字母是'D',则这两个人属于不同黑帮

若前面字母是'A',则询问你这两个人是否属于同一个黑帮或是不确定

解法:

令p[x]为x的父节点,若p[x]!=p[y]则两个人中至少有一个人在之前的数据中还没出现过,不能确定状态

若p[x]==p[y]且r[x]==r[y],则两个人属于同一个黑帮

否则属于不同的黑帮

用并查集的难点在于如何路径压缩

对于每次给出的数据,给出'D a b' 

x = find(a);

y = find(b);

若当前p[x]==p[y],则两个人均出现过,不需要操作

否则令p[y]==x,将y的父节点设为x,对应r[y]应该怎么求呢?

对于r[a] r[b],因为在find的过程中进行了路径压缩,所以当前r[a] r[b]对应的是和x y的关系

现下列出一种情况:

当r[x] == r[a] =0 r[y]==r[b]=0时

说明a x属于同一个黑帮,b y属于同一个黑帮

因为D a b,故x y必然不属于同一个黑帮

所以处理后r[y]应该等于1

其他情况不再一一列举

给出对应关系r[y] = r[a]^1^r[b]//对应同或关系

代码如下:

#include <cstdio>
#include <iostream>
#define MAXN 100001
using namespace std;

int r[MAXN], p[MAXN];

int find(int x) {
    int tmp;
    if(x != p[x]) {
        tmp = p[x];
        p[x] = find(p[x]);
        r[x] ^= r[tmp];
    }
    return p[x];
}

int main(void) {
    int T, a, b, x, y, i, n, m;
    char ch[10];
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        for(i=1; i<=n; ++i) {
            p[i] = i;
            r[i] = 0;
        }
        while(m--) {
            scanf("%s%d%d", ch, &a, &b);
            x = find(a);
            y = find(b);
            if(ch[0] == 'A') {
                if(x != y)
                    puts("Not sure yet.");
                else if(r[a] == r[b])
                    puts("In the same gang.");
                else puts("In different gangs.");
            } else {
                if(x != y) {
                    p[y] = x;
                    r[y] = r[a]^1^r[b];
                }
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值