1.并查集概念
查找一个元素所属集合
合并两个元素各自所属的集合
2.涉及到的操作
并查集初始化
主要是利用数组存储树形结构,初始化的时候将数组元素初始化为自身
路径压缩
将根结点下的所有结点均变为根结点的孩子结点,进而降低查询的深度,降低时间复杂度
集合合并
将秩小的树连接到秩大的树上
3.等价问题
题目:
Input:
输入的第一行包含两个用空格隔开的正整数n和k,其中n不超过100,k不超过n-1。之后的k行中,每行包含两个用空格隔开的正整数x和y,表示将x元素所在的集合和y元素所在的集合合并至同一个集合。保证x和y均在1至n之间。最后一行中,包含两个正整数,表示需要判断是否在同一个集合的元素编号。
Output:
共一行,包含字符串“YES”或“NO”,“YES”表示需判断的元素在同一个集合中,“NO”表示不在同一个集合中。请注意不需要输出引号,且行尾输出换行。
样例输入:
5 3
1 3
2 3
1 4
2 4
样例输出:
YES
实现代码:
1 #include<stdio.h>
2 #define MaxSize 50
3 int id[MaxSize]; //存储集合间关系
4 int rank[MaxSize]; //存储树的高度
5
6 //并查集数组初始化为自身,并且初始化树的秩为 1
7 void set(int n) {
8 int i;
9 for (i = 0; i < n; i++) {
10 id[i] = i;
11 rank[i] = 1;
12 }
13 }
14
15 //找到集合的根结点(即并查集数组的代表结点)
16 int find(int x) {
17 int r = x;
18 while(r != id[r]) {
19 //将 r 结点的父亲结点设置为它的爷爷结点
20 //相当于在寻找根结点的同时对路径进行了压缩
21 id[r] = id[id[r]];
22 r = id[r];
23 }
24 //路径压缩法 2 :(将根结点下的所有结点变为根结点的孩子)
25 /*int temp;
26 while(x != r) {
27 temp = id[x];
28 id[x] = r;
29 x = temp;
30 }*/
31 return r;
32 }
33
34 //将两个元素的集合进行合并
35 //将树的秩较小的树根指向秩较大的树
36 //然后较大秩的树秩加上较小秩的树秩
37 void Union(int x, int y) {
38 if((x = find(x)) == (y = find(y))) {
39 return;
40 }
41 if(rank[x] < rank[y]) {
42 id[x] = y;
43 rank[y] += rank[x];
44 } else {
45 id[y] = x;
46 rank[x] += rank[y];
47 }
48 }
49
50 int main(){
51 int n, k;
52 if (scanf("%d %d", &n, &k))
53 set(n + 1);
54 int i;
55 int p, q;
56 for (i = 1; i < k + 1; i++) {
57 if (scanf("%d %d", &p, &q)) {
58 Union(p, q);
59 }
60 }
61 if (scanf("%d %d", &p, &q))
62 if(find(q) == find(q)) {
63 printf("YES\n");
64 } else {
65 printf("NO\n");
66 }
67 return 0;
68 }
部分图片解释:
4.总结
几天前查阅资料完成的,到现在才整理出来。。。不过又熟悉了一种高效的算法,感觉不错。。。嘿嘿~