两种考察连通性的算法:
- Quick_find算法:将所有元素的代表元素设为后面merge的元素,最后会呈现出表格中有几个元素就有几类的情况,但每次更新权值都要进行所有元素的搜索,很慢。
- Quick_union算法:将每个集合的代表元素改成一样的,比如2->1,那么将2与3并时,只需将1->3。判断是否属于一个集合需要递归找到自己就是代表元素的节点,就是这个集合的根结点,此时也是,有几个集合就有几个树。
Quick_union优化:
- 根据权值(子节点数量)决定谁是爸爸
- 路径压缩:在搜索代表节点时,找如果不是直接挂在根上的,就把他的直系父亲节点改为根。
#include <stdio.h>
#include <stdlib.h>
typedef struct UnionSet{
int *color;
int *size;//记录每个节点下子节点个数
int n;
}UnionSet;
UnionSet *init(int n){
UnionSet *u = (UnionSet *)malloc(sizeof(UnionSet));
u->color = (int *)malloc(sizeof(int) * (n + 1));
u->size = (int *)malloc(sizeof(int) * (n + 1));
u->n = n;
for (int i = 0; i < n; i++){
u->color[i] = i;
u->size[i] = 1;
}
return u;
}
int find(UnionSet *u, int x){
return u->color[x] = (u->color[x] == x ? x : find(u, u->color[x]));
}
int merge(UnionSet *u, int a, int b){
int fa = find(u, a), fb = find(u, b);
if (fa == fb) return 0;
if (u->size[fa] > u->size[fb]){
int t = fa;
fa = fb;
fb = t;
}
//int color_a = u->color[a];//要多设一个变量不然中途会变
// for (int i = 0; i < u->n; i++){
// if (u->color[i] == color_a){
// u->color[i] = u->color[b];
// u->size[b] += u->size[a];
// }
// }
u->color[fa] = fb;
u->size[fb] += u->size[fa];
return 1;
}
int main(){
int n, m;
scanf("%d%d", &n, &m);
UnionSet *u = init(n);
for (int i = 0; i < m; i++){
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
switch(a){
case 1:merge(u, b, c);break;
case 2:printf("%s\n", find(u, b)==find(u, c) ? "YES" : "NO");
}
}
return 0;
}