码迷,mamicode.com
首页 > 其他好文 > 详细

并查集 - 1611 The Suspects

时间:2015-10-05 01:55:20      阅读:253      评论:0      收藏:0      [点我收藏+]

标签:

题目地址: http://poj.org/problem?id=1611

分析: 

  - 数据结构

    - parent[x] 表示 x 元素的父节点位置.

    - rank[x] 记录x的子链的长度, 以便在合并的时候减少链条长度. 查找的时候使用了路劲压缩, 所以两个节点的rank差不会大于1, 所以提高的效率也不是很大, 但还是很有帮助.

    - quantity[x] 表示x的子节点的个数(包含自身). 对于根节点来说, 就是这个集合的大小.

  - build(n) 由于规模 n 在变化, 所以需要多大的规模就只初始化那一部分即可. 

  - findx(x) 找到x所在集合的根节点的编号, 并且将路径压缩至1(每个节点直接指向父节点)

  - mergexy(x,y) 按照rank大小合并, 并且更新quantity和rank

  - 下面的代码中, 如果将  while(m-- && scanf("%d",&k)==1)  改为:  while(scanf("%d",&k)==1 && m--) 则会出现错误, 因为当m == 0  的时候本来没有group, k应该没有, 但是还是scanf将下一组的数据输入了,  所以会造成TLE.

  - 代码如下:

#include <stdio.h>

#define MAXNUM 30100

//parent[i]记录i号节点对应的父节点编号. 它们属于同一个集合.
int parent[MAXNUM];
//quantity[i]记录指向i或者i的子节点的节点个数.对于根节点即集合大小(指向自身).
int quantity[MAXNUM];
//rank[i] 记录i的深度, 以便建立一棵平衡的树.
int rank[MAXNUM];

void build(int n){
    for(int i=0;i<n;i++){
        parent[i] = i;
        rank[i] = 0;
        quantity[i] = 1;
    }
}

// 找到x所在的集合的根节点.并压缩路径
int findx(int x){
    int r = x;
    int t;
    while(parent[r] != r){
        r = parent[r];
    }
    //将r的所有间接子节点直接指向r本身, 压缩了路径.
    while(r != x && parent[x] != x){
        t = parent[x];
        parent[x] = r;
        x = t;
    }
    return x;
}

// 将x,y所在的集合合并
void mergexy(int x, int y){
    int rootx = findx(x);
    int rooty = findx(y);
    if (rootx == rooty)
        return;
    // 根据秩的大小合并
    if(rank[rootx] > rank[rooty]){
        parent[rooty] = rootx;
        quantity[rootx] += quantity[rooty];
    }else if(rank[rootx] == rank[rooty]){
        parent[rootx] = rooty;
        quantity[rooty] += quantity[rootx];
        rank[rooty]++;
    }else{
        parent[rootx] = rooty;
        quantity[rooty] += quantity[rootx];
    }
}

int main(){
    int n,m;
    while(scanf("%d%d",&n,&m) && (n || m)){
        //初始化数据结构
        build(n);
        int k,x,y;
        while(m-- && scanf("%d",&k)==1){
            scanf("%d",&x);
            for(int i=1;i<k;++i){
                scanf("%d",&y);
                mergexy(x,y);
            }
        }
        printf("%d\n",quantity[findx(0)]);
    }
    return 0;
}

 

POJ 2524 - Ubiquitous Religions 和这个题很相似, 稍微改几行代码就可以提交了.

题目链接: http://poj.org/problem?id=2524

代码如下:

技术分享
 1 #include <stdio.h>
 2 
 3 #define MAXNUM 50010
 4 
 5 int parent[MAXNUM];
 6 int quantity[MAXNUM];
 7 int rank[MAXNUM];
 8 void build(int n){
 9     for(int i=0;i<n;i++){
10         parent[i] = i;
11         rank[i] = 0;
12         quantity[i] = 1;
13     }
14 }
15 int findx(int x){
16     int r = x;
17     int t;
18     while(parent[r] != r){
19         r = parent[r];
20     }
21     while(r != x && parent[x] != x){
22         t = parent[x];
23         parent[x] = r;
24         x = t;
25     }
26     return x;
27 }
28 void mergexy(int x, int y){
29     int rootx = findx(x);
30     int rooty = findx(y);
31     if (rootx == rooty)
32         return;
33     if(rank[rootx] > rank[rooty]){
34         parent[rooty] = rootx;
35         quantity[rootx] += quantity[rooty];
36     }else if(rank[rootx] == rank[rooty]){
37         parent[rootx] = rooty;
38         quantity[rooty] += quantity[rootx];
39         rank[rooty]++;
40     }else{
41         parent[rootx] = rooty;
42         quantity[rooty] += quantity[rootx];
43     }
44 }
45 int main(){
46     int n,m;
47     int kiss=1;
48     while(scanf("%d%d",&n,&m) && (n || m)){
49         build(n);
50         int x,y;
51         while(m-- && scanf("%d%d",&x,&y)==2){
52             mergexy(x,y);
53         }
54         int sum = 0;
55         for (int i=0;i<n;++i){
56             if(parent[i] == i)
57                 sum ++;
58         }
59         printf("Case %d: %d\n",kiss++,sum);
60     }
61     return 0;
62 }
View Code

 

并查集 - 1611 The Suspects

标签:

原文地址:http://www.cnblogs.com/roger9567/p/4855249.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!