zoukankan      html  css  js  c++  java
  • [POJ]并查集三连发

    整理一下最近的题解,这是三个并查集的题目,分别是:

    POJ 1182 食物链
    POJ 1611 The Suspects
    POJ 2524 Ubiquitous Religions

    POJ 1182 食物链

    这个题有一个很棒的套路,那就是用一个并查集来维护三个集合内的元素,可以使这个并查集扩大n倍,然后按照元素是属于哪一个集合来进行运算,放入并查集对应范围内的对应位置。代码如下:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    const int maxn = 0x7ffffff;
    int pre[maxn];
    
    int find(int x) {
        return x == pre[x] ? x : pre[x] = find(pre[x]);
    }
    
    void unite(int x, int y) {
        x = find(x);
        y = find(y);
        if(x != y) {
            pre[y] = x;
        }
    }
    
    int main() {
        int N, K, D, x, y;
        scanf("%d %d", &N, &K);
        int mm = N * 3;
        for(int i = 0; i < mm; i++) {
            pre[i] = i;
        }
        int ans = 0;
        
        while(K--) {
            scanf("%d %d %d", &D, &x, &y);
            if(x > N || y > N) {
                ans++;
                continue;
            }
            if(D == 1) {    //同类
                if(find(x) == find(y+N) || find(x) == find(y+2*N)) {
                    ans++;  //矛盾
                }
                else {
                    unite(x, y);        //放入A
                    unite(x+N, y+N);    //放入B
                    unite(x+2*N, y+2*N);//放入C
                }
            }
            else if(D == 2) {   //不同类
                if(find(x) == find(y) || find(x) == find(y+2*N)) {
                    ans++;  //矛盾
                }
                else {
                    unite(x, y+N);      //x放入A,y放入B
                    unite(x+N, y+2*N);  //x放入B,y放入C
                    unite(x+2*N, y);    //x放入B,y放入A
                }
            }
        }
        printf("%d
    ", ans);
    }
    View Code

    POJ 1611 The Suspects

    这道题可以在输入的时候进行处理,单独读入一个元素后,再循环读入剩下的,再与每一个元素的前者进行合并操作(如果不是同一个father)。在并查集的unite操作中来动态统计合并到某两个元素的时候此时的suspects的数量,这样的话,只需要找到0号的father就可以找到suspects的总人数了(默认0是患病的)。代码如下:

     1 #define _CRT_SECURE_NO_WARNINGS
     2 #include <cstdlib>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <iostream>
     6 
     7 using namespace std;
     8 
     9 const int maxn = 30010;
    10 int father[maxn];
    11 int num[maxn];
    12 int n, m;
    13 
    14 void init() {
    15     for (int i = 0; i < maxn; i++) {
    16         father[i] = i;
    17         num[i] = 1;
    18     }
    19 }
    20 int find(int x) {
    21     return x == father[x] ? x : father[x] = find(father[x]);
    22 }
    23 void unite(int x, int y) {
    24     x = find(x);
    25     y = find(y);
    26     if(x != y) {    
    27         father[x] = y;
    28         num[y] += num[x];
    29     }
    30 }
    31 
    32 int main(int argc, char *argv[]) {
    33     while (~scanf("%d %d", &n, &m) && n + m) {
    34         init();
    35         int group;
    36         int tmp[maxn];
    37         int ans = 0;
    38         for (int ii = 0; ii < m; ii++) {
    39             memset(tmp, 0, sizeof(tmp));
    40             scanf("%d", &group);
    41             scanf("%d", &tmp[0]);
    42             for (int i = 1; i < group; i++) {
    43                 scanf("%d", &tmp[i]);
    44                 if (father[tmp[i]] != father[tmp[i - 1]]) {
    45                     unite(tmp[i], tmp[i - 1]);
    46                 }
    47             }
    48         }
    49         // for (int i = 0; i < n; i++) {
    50         //     if (father[i] == 0) {
    51         //         ans++;
    52         //     }
    53         // }
    54         printf("%d
    ", num[find(0)]);
    55     }
    56     return 0;
    57 }
    View Code

    POJ 2524 Ubiquitous Religions

    额外加一个vis来判断某信仰是否被遍历到,利用并查集“合并过的两个元素其中一个元素的father必定不是本身”这一性质统计一共有多少个集合。代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 
     7 const int maxn = 50010;
     8 int pre[maxn];
     9 int vis[maxn];
    10 int n, m;
    11 
    12 int find(int x) {
    13     return x == pre[x] ? x : pre[x] = find(pre[x]);
    14 }
    15 
    16 void unite(int x, int y) {
    17     x = find(x);
    18     y = find(y);
    19     if(x != y) {
    20         pre[y] = x;
    21     }
    22 }
    23 inline void init() {
    24     for(int i = 0; i < maxn; i++) {
    25         pre[i] = i;
    26     }
    27 }
    28 
    29 int main() {
    30     int kase = 1;
    31     while(~scanf("%d %d", &n, &m) && n+m) {
    32         init();
    33         memset(vis, 0, sizeof(vis));
    34         int a, b;
    35         int cnt = 0;
    36         for(int i = 0; i < m; i++) {
    37             scanf("%d %d", &a, &b);
    38             vis[a] = 1; 
    39             vis[b] = 1;
    40             unite(a, b);
    41         }
    42         int k = 0;
    43         // for(int i = 1; i <= n; i++) {
    44         //  cout << pre[i] << " ";
    45         // }
    46         // cout << endl;
    47         for(int i = 1; i <= n; i++) {
    48             if(vis[i] && pre[i] == i) {
    49                 cnt++;
    50             }
    51             if(!vis[i]) {
    52                 cnt++;
    53             }
    54         }
    55         printf("Case %d: %d
    ", kase++, cnt);
    56     }
    57     return 0;
    58 }
    View Code
  • 相关阅读:
    如何用js刷新aspxgridviw
    ASPxSpinEdit 控件的三元判断
    关于cookie
    asp.net解决数据转换为DBNULL的问题
    Devexpress 中如何写ASPxGridView新增修改时的数据验证
    ASPxGridView中批量提交及个别提交的写法
    c#中如何做日期的三元判断(日期不为空赋值)
    c#中如何不通过后台直接用js筛选gridview中的数据条件筛选查询?
    devexpress中如何绑定ASPxTreeList控件
    如何在后台动态生成ASPxCheckBoxList标签并循环(数据调用存储过程)
  • 原文地址:https://www.cnblogs.com/kirai/p/4769265.html
Copyright © 2011-2022 走看看