标签:
题目地址: 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 }
标签:
原文地址:http://www.cnblogs.com/roger9567/p/4855249.html