C语言实现判断连通性之并查集 Quick-Find算法 Quick-Union算法 weighted-quickUnion算法 路径压缩算法

  • 题目描述

所谓一个朋友圈子,不一定其中的人都互相直接认识。
​例如:小张的朋友是小李,小李的朋友是小王,那么他们三个人属于一个朋友圈。
现在给出一些人的朋友关系,人按照从 1 到 𝑛 编号在这中间会进行询问某两个人是否属于一个朋友圈,请你编写程序,实现这个过程。

输入
第一行输入两个整数 𝑛,𝑚(1≤𝑛≤10000,3≤𝑚≤100000),分别代表人数和操作数。
接下来 𝑚 行,每行三个整 𝑎,𝑏,𝑐(𝑎∈[1,2], 1≤𝑏,𝑐≤𝑛)
当 𝑎=1 时,代表新增一条已知信息,𝑏,𝑐 是朋友
当 𝑎=2 时,代表根据以上信息,询问 𝑏,𝑐 是否是朋友

输出
对于每个 𝑎=2 的操作,输出『𝑌𝑒𝑠』或『𝑁𝑜』代表询问的两个人是否是朋友关系。


  • 代码
#include <stdio.h>
#include <stdlib.h>

#if 0
///判断连通性之并查集 Quick-Find算法 基于染色思想:
/// 一开始每个人的颜色都不一样
/// 连接两个点时,把这两个点设置成一个颜色
/// 若颜色一样为一伙,则不是
/// 查询O(1) 合并O(n)
typedef struct UnionSet {
    int *color, size;
} UnionSet;

UnionSet *initSet(int n) {
    UnionSet *u = (UnionSet *)malloc(sizeof(UnionSet));
    u->color = (int *)malloc(sizeof(int) * (n + 1));
    u->size = n + 1;
    for (int 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 ind) {
    return u->color[ind];
}

int merge(UnionSet *u, int a, int b) {
    int acolor = find(u, a);
    if (acolor == find(u, b)) return 0;
    for (int i = 0; i < u->size; ++i)
        if (find(u, i) == acolor)
            u->color[i] = u->color[b];
    return 1;
}
#endif

#if 0
///判断连通性之并查集 Quick-Union算法:
/// 一开始每个人的都是自己一个队友
/// 连接队友时,让ta没有队友的队友把你没有队友的队友作为队友
/// 若两人没有队友的队友是同一人,则他们是队友
/// 查询+合并多时间复杂度都为树多高度
typedef struct UnionSet {
    int *father, 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 ind) {
    while (u->father[ind] != ind)
        ind = u->father[ind];
    return ind;
}

int merge(UnionSet *u, int a, int b) {
    if (find(u, a) == find(u, b)) return 0;
    u->father[find(u, a)] = find(u, b);
    return 1;
}
#endif

#if 0
///判断连通性之并查集 weighted quickUnion算法:
///少数服从多数:根据节点个数,节点少的合并到节点多多
/// 连通判断 + 合并操作都为 O(logn)
typedef struct UnionSet {
    int *father, *len, size;//len记录树有多少节点
} 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 ind) {
    while (u->father[ind] != ind)
        ind = u->father[ind];
    return ind;
}

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;
}
#endif

///路径压缩算法
///查询+合并几乎都为O(1)
typedef struct UnionSet {
    int *father, size;//len记录树有多少节点
} 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 ind) {
    while (u->father[ind] != ind)
        ind = u->father[ind];
    return u->father[ind] = ind;
    //return u->father[ind] = u->father[ind] == ind ? ind : find(u, u->father[ind]);
}

int merge(UnionSet *u, int a, int b) {
    if (find(u, a) == find(u, b)) return 0;
    u->father[find(u, a)] = find(u, b);
    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;
}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值