【并查集】POJ 1703 Find them, Catch them

POJ 1703 : Find them, Catch them

有两大帮派,现在不知道每个人的帮派情况。有两种操作,D x y 表示x和y在不同帮派,A x y查询x和y的帮派情况。
如果在同一帮派,输出In the same gang.
如果不在同一帮派,输出In different gangs.
不确定帮派情况则输出Not sure yet.

这里是POJ 1182 食物链 的同类型题目。
这个时候维护1~N为A帮派,N+1~2*N为B帮派。
如果Find(x) == Find(y + N)则代表一个在A帮派,一个在B帮派。
如果Find(x) == Find(y)则代表在同一个帮派。
其余则不确定情况。

需要注意的是当n = 2 时,需要特别判断下。

代码

#include <iostream>
#include <cstdio>
#include <map>
using namespace std;

const int MAXNUM = 2* (100000 + 10);
int id[MAXNUM];
int Size[MAXNUM];
// 初始化
void make_set(int n){
    for(int i = 1 ; i <= n ; i++){
        id[i] = i;
        Size[i] = 1;
    }
}

// 查找父节点
int Find(int p) {
    while (p != id[p]) {
        // 路径压缩,会破坏掉当前节点的父节点的尺寸信息,因为压缩后,当前节点的父节点已经变了
        id[p] = id[id[p]];
        p = id[p];
    }
    return p;
}

// 合并 p ,q节点
void Union(int p, int q) {
    int pRoot = Find(p);
    int qRoot = Find(q);

    if (pRoot == qRoot) {
        return;
    }
    // 按秩进行合并
    if (Size[pRoot] > Size[qRoot]) {
        id[qRoot] = pRoot;
        Size[pRoot] += Size[qRoot];
    } else {
        id[pRoot] = qRoot;
        Size[qRoot] += Size[pRoot];
    }
}

int main(){
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    int t;
    int n,m;
    char c;
    int p,q;
    int p1 ,p2 ;
    scanf("%d", &t);
    while(t--){
        scanf("%d %d", &n, &m);
        make_set(n * 2);
        for(int i = 0 ; i < m ; i++){
            getchar();
            scanf("%c %d %d", &c , &p, &q);
            // 查询
            if(c=='A'){
                if(n == 2){
                    if(Find(p) == Find(q + n))
                        printf("In the same gang.\n");
                    else
                        printf("In different gangs.\n");
                    continue;
                }

                if(Find(p) == Find(q + n)){
                    printf("In different gangs.\n");
                }else if(Find(p) == Find(q)){
                    printf("In the same gang.\n");
                }else{
                    printf("Not sure yet.\n");
                }
            }else{
                Union(p, q + n);
                Union(p + n , q);
            }
        }
    }
    return 0;
}

代码

#include <iostream>
#include <cstdio>
#include <map>
using namespace std;

const int MAXNUM = 2* (100000 + 10);
int id[MAXNUM];
int Size[MAXNUM];
int r[MAXNUM];

// 初始化
void make_set(int n){
    for(int i = 1 ; i <= n ; i++){
        id[i] = i;
        Size[i] = 1;
        r[i] = 0;
    }
}

// 查找父节点
int Find(int p) {
     while (id[p] != id[id[p]]) {   //如果q不是其所在子树的根节点的直接孩子
        r[p] = (r[p] + r[id[p]] ) % 2;
         id[p] = id[id[p]];          //对其父节点到其爷爷节点之间的路径进行压缩
      }
    return id[p];
}

// 合并 p ,q节点
void Union(int p, int q, int d) {
    int pRoot = Find(p);
    int qRoot = Find(q);

    if (pRoot == qRoot) {
        return;
    }
    id[qRoot] = pRoot;
    r[qRoot] = (r[p] - r[q] + 2 + (d)) % 2;
}

int main(){
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    int t;
    int n,m;
    char c;
    int p,q;
    int p1 ,p2 ;
    scanf("%d", &t);
    while(t--){
        scanf("%d %d", &n, &m);
        make_set(n);
        for(int i = 0 ; i < m ; i++){
            getchar();
            scanf("%c %d %d", &c , &p, &q);
            // 查询
            if(c=='A'){
                if(n == 2){
                    if(r[p] == r[q])
                        printf("In the same gang.\n");
                    else
                        printf("In different gangs.\n");
                    continue;
                }

                if(Find(p) == Find(q)){
                    if(r[p] != r[q]){
                        printf("In different gangs.\n");
                    }else{
                        printf("In the same gang.\n");
                    }
                }else{
                    printf("Not sure yet.\n");
                }
            }else{
                Union(p, q, 1);
            }
        }
    }
    return 0;
}
点赞