天天看点

【并查集】POJ 2492 :A Bug's Life

POJ 2492 : A Bug’s Life

编号1~n的Bugs,给出不同性别的m对,证明是否有同性恋的Bugs。

可以看出题目是含有关系的并查集,将1~n归为男性,n+1~2 * n为女性。

当查询Find(x) == Find(y)时,证明含有错误的列表,则输出Suspicious bugs found!,

否则则合并x,y(Union(x,y + n),Union(x + n , y)操作)

代码

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

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

// 查找父节点
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 Case = ;
    int n, m ;
    int p, q;
    int t;
    scanf("%d", &t);
    while(t--){
        bool ans = true;
        scanf("%d %d", &n, &m);
        make_set(n * );
        for(int i =  ; i < m ; i++){
            scanf("%d %d", &p, &q);
            if(Find(p) == Find(q))
                ans = false;
            else{
                Union(p, q + n);
                Union(p + n, q);
            }
        }
        printf("Scenario #%d:\n",Case++);
        if(ans)
            printf("No suspicious bugs found!\n\n");
        else
            printf("Suspicious bugs found!\n\n");
    }

    return ;
}
           

代码

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

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

// 查找父节点
int Find(int p) {
    while (id[p] != id[id[p]]) {   //如果q不是其所在子树的根节点的直接孩子
        r[p] = (r[p] + r[id[p]] ) % ;
         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] + d) % ;
}

int main(){
    //freopen("input.txt","r",stdin);
    //freopen("output.txt","w",stdout);
    int Case = ;
    int n, m ;
    int p, q;
    int t;
    scanf("%d", &t);
    while(t--){
        bool ans = true;
        scanf("%d %d", &n, &m);
        make_set(n);
        for(int i =  ; i < m ; i++){
            scanf("%d %d", &p, &q);
            if(Find(p) == Find(q) && r[p] == r[q])
                ans = false;
            else{
                Union(p, q , );
            }
        }
        printf("Scenario #%d:\n",Case++);
        if(ans)
            printf("No suspicious bugs found!\n\n");
        else
            printf("Suspicious bugs found!\n\n");
    }

    return ;
}
           

继续阅读