并查集

简介: 文章目录前言一、例题,代码1.AcWing 836. 合并集合本题分析AC代码2.AcWing 837. 连通块中点的数量关于本题AC代码3.AcWing 240. 食物链关于本题AC代码二、时间复杂度

文章目录

前言

一、例题,代码

1.AcWing 836. 合并集合

本题分析

AC代码

2.AcWing 837. 连通块中点的数量

关于本题

AC代码

3.AcWing 240. 食物链

关于本题

AC代码

二、时间复杂度


前言

复习acwing算法基础课的内容,本篇为讲解基础算法:并查集,关于时间复杂度:目前博主不太会计算,先鸽了,日后一定补上。


一、例题,代码

1.AcWing 836. 并集

本题链接:合并集合

本博客给出本题的截图:

image.png

本题分析

如何合并两个集合:让它们的父节点相等


刚开始对于每一个点都是一个单独的集合

数组p代表着父节点,例如p[i]的值就是i的父节点的值

p数组的初始化p[i] = i;,如何合并两个集合呢?例如合并3和5这两个数所在的集合

那么一开始p[3] = 3, p[5] = 5,我们令p[3] = p[5] = 5,这一步的操作是让3的父节点指向5,即让5是3的父节点,我们写成p[5] = p[3] = 3也是可以的,二者没有本质的差别


那么如果我们紧接着想让2和3所在的集合进行合并,我们知道了现在3和5是在一个集合的,并且3的父节点是5,那么我们执行p[2] = p[find(3)],find(x)函数为查找x的父节点,执行完这个操作我们可以让2的父节点也指向5,从而达到集合合并的目的


find函数:我们查找p[x]和x是否相等,因为我们一开始都是让p[i] = i;,如果不相等,证明该点和别的集合进行了合并,那么我们就去继续寻找该点的父节点即p[x] = find(p[x].


AC代码

#include <cstdio>
using namespace std;
const int N = 100010;
int p[N];
int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    return p[x];
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++ ) p[i] = i;
    while (m -- )
    {
        char op[2];
        scanf("%s", op);
        int a, b;
        scanf("%d%d", &a, &b);
        if (op[0] == 'M') p[find(a)] = find(b);
        else
            if (p[find(a)] == find(b)) puts("Yes");
            else puts("No");
    }
    return 0;
}

2.AcWing 837. 连通块中点的数量

本题链接:AcWing 837. 连通块中点的数量

本博客给出本题截图:

image.png

关于本题

相较于上一个题,我们还需要多维护一个cnt数组,因为每一个数一开始都是一个集合,所以每个集合的初始值为1,即cnt[i] = 1;

AC代码

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int N = 100010;
int p[N], cnt[N];
int find(int x)
{
    if (p[x] != x) p[x] = find(p[x]);
    else return p[x];
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i ++ )
    {
        p[i] = i;
        cnt[i] = 1;
    }
    while (m -- )
    {
        string op;
        cin >> op;
        if (op == "C")
        {
            int a, b;
            scanf("%d%d", &a, &b);
            if (find(a) != find(b))
            {
                cnt[find(b)] += cnt[find(a)];
                p[find(a)] = find(b);
            }
        }
        else if (op == "Q1")
        {
            int a, b;
            scanf("%d%d", &a, &b);
            if (p[find(a)] == p[find(b)]) puts("Yes");
            else puts("No");
        }
        else
        {
            int x;
            scanf("%d", &x);
            printf("%d\n", cnt[find(x)]);
        }
    }
    return 0;
}

3.AcWing 240. 食物链

本题链接:AcWing 240. 食物链

本博客给出本题截图:

image.png

image.png

关于本题

分析过程有点复杂,文字性语言不好说清,未来会放一个文字版解释或一个视频讲解,先鸽

若有视频讲解,链接为(先鸽)

AC代码

#include <cstdio>
using namespace std;
const int N = 50010;
int p[N], d[N];
int find(int x)
{
    if (p[x] != x)
    {
        int t = find(p[x]);
        d[x] += d[p[x]];
        p[x] = t;
    }
    return p[x];
}
int main()
{
    int n, k;
    scanf("%d%d", &n, &k);
    for (int i = 0; i < n; i ++ ) p[i] = i;
    int res = 0;
    while (k -- )
    {
        int x, y, q;
        scanf("%d%d%d", &q, &x, &y);
        int px = find(x), py = find(y);
        if (x > n || y > n) res ++;
        else 
        {
            if (q == 1)
            {
                if (px == py && (d[x] - d[y]) % 3) res ++;
                else if (px != py)
                {
                    p[px] = py;
                    d[px] = d[y] - d[x];
                }
            }
            else
            {
                if (px == py && (d[x] - d[y] - 1) % 3) res ++;
                else if (px != py)
                {
                    p[px] = py;
                    d[px] = d[y] + 1 - d[x];
                }
            }
        }
    }
    printf("%d", res);
    return 0;
}

二、时间复杂度

关于并查集算法的时间复杂度以及证明,后续会给出详细的说明以及证明过程,目前先鸽了。


目录
相关文章
|
6月前
|
算法
并查集,路径压缩
并查集,路径压缩
43 0
|
6月前
并查集。。
并查集。。
34 0
并查集及其应用
并查集及其应用
66 0
|
6月前
|
算法 测试技术
并查集算法
并查集算法
|
6月前
|
机器学习/深度学习
并查集(UnionFind)总结
并查集(UnionFind)总结
64 0
|
算法
并查集模板题
并查集模板题
49 0
|
存储 算法 iOS开发
并查集详解及应用
并查集详解及应用
3851 0