目录
0. 并查集(解决连通性问题)
1. quickFind(染色)
#include <stdio.h>
#include <stdlib.h>
typedef struct UnionSet{
int *color;
int size;
} UnionSet;
UnionSet *initSet(int n){
UnionSet *u=(UnionSet *)malloc(sizeof(UnionSet));
u->color=(int *)malloc(sizeof(int)*(n+1));
u->size=n+1;//#oj-71
int i;
for(i=0;i<u->size;i++){
u->color[i]=i;
}
return u;
}
void freeSet(UnionSet *u){
if(!u)
return ;
free(u->color);
free(u);
return ;
}
int find(UnionSet *u,int idx){
return u->color[idx];
}
int merge(UnionSet *u,int a,int b){
if(find(u,a)==find(u,b))
return 0;
int acolor=find(u,a);
int i;
for(i=0;i<u->size;i++){
if(find(u,i)==acolor)
u->color[i]=u->color[b];
}
return 1;
}
int main(void){
int n,m,i;
scanf("%d%d",&n,&m);
UnionSet *u=initSet(n);
for(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");
break;
}
}
freeSet(u);
return 0;
}
2. quickUnion(我队友的队友就是我的队友)
⭐find和merge都是对根节点进行操作,merge时直接连接根节点,减少树的层数,查询效率高
#include <stdio.h>
#include <stdlib.h>
typedef struct UnionSet{
int *father;
int size;
}UnionSet;
UnionSet *initSet(int n){
UnionSet *u=(UnionSet *)malloc(sizeof(UnionSet));
u->father=(int *)malloc(sizeof(int)*(n+1));
u->size=n+1;
int i;
for(i=0;i<u->size;i++){
u->father[i]=i;
}
return u;
}
void freeSet(UnionSet *u){
if(!u)
return ;
free(u->father);
free(u);
return ;
}
int find(UnionSet *u,int idx){
//路径压缩 idx的父节点赋值为find最终结果
return u->father[idx]=u->father[idx]==idx?idx:find(u,u->father[idx]);
}
int merge(UnionSet *u,int a,int b){
int fa=find(u,a),fb=find(u,b);
if(fa==fb)
return 0;
u->father[fa]=fb;
return 1;
}
int main(void){
int n,m,i;
scanf("%d%d",&n,&m);
UnionSet *u=initSet(n);
for(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");
break;
}
}
freeSet(u);
return 0;
}
3. weightedQuickUnion(少数服从多数)
⭐优化思考:根据节点数量作为合并的依据,即按秩合并
#include <stdio.h>
#include <stdlib.h>
typedef struct UnionSet {
int *father;
int *len;
int size;
} UnionSet;
UnionSet *initSet(int n) {
UnionSet *u = (UnionSet *)malloc(sizeof(UnionSet));
u->father = (int *)malloc(sizeof(int) * (n + 1));
u->len = (int *)malloc(sizeof(int) * (n + 1));
u->size = n + 1;
for (int i = 0; i < u->size; i++) {
u->father[i] = i;
u->len[i] = 1;
}
return u;
}
void freeSet(UnionSet *u) {
if (!u) return ;
free(u->father);
free(u->len);
free(u);
return ;
}
int find(UnionSet *u, int x) {
return u->father[x] = u->father[x] == x ? x : find(u, u->father[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->len[fa] > u->len[fb]) {
u->father[fb] = fa;
u->len[fa] += u->len[fb];
} else {
u->father[fa] = fb;
u->len[fb] += u->len[fa];
}
return 1;
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
UnionSet *u = initSet(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");
break;
}
}
freeSet(u);
return 0;
}
4. 路径压缩(按秩合并会退化为链表)
- 有了路径压缩,就不同时使用按秩合并了,因为压缩的效率已经非常高
- merge(0, 6)会把0,1,3直接挂到9上
#include <stdio.h>
#include <stdlib.h>
typedef struct UnionSet {
int *father;
int size;
} UnionSet;
UnionSet *initSet(int n) {
UnionSet *u = (UnionSet *)malloc(sizeof(UnionSet));
u->father = (int *)malloc(sizeof(int) * (n + 1));
u->size = n + 1;
for (int i = 0; i < u->size; i++) u->father[i] = i;
return u;
}
void freeSet(UnionSet *u) {
if (!u) return ;
free(u->father);
free(u);
return ;
}
int find(UnionSet *u, int x) {
return u->father[x] = u->father[x] == x ? x : find(u, u->father[x]); // 路径压缩
}
int merge(UnionSet *u, int a, int b) {
int fa = find(u, a), fb = find(u, b); // find时路径压缩
if (fa == fb) return 0;
u->father[fa] = fb; // 路径压缩,未按秩合并
return 1;
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
UnionSet *u = initSet(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");
break;
}
}
freeSet(u);
return 0;
}