首页 > 其他分享 >并查集(Disjoint Set)

并查集(Disjoint Set)

时间:2023-07-13 10:13:50浏览次数:33  
标签:cnt Set int 查集 查询 集合 权值 Disjoint

并查集是算法竞赛中常用的一种数据结构。

其主要功能是查询两个元素是否在同一个集合以及将两个集合合并

第一部分 并查集的基本操作

算法思想

  1. 我们将所有元素建成很多树(森林),每一棵树就是一个集合,比如下图有 \(\{1, 2, 3, 4, 5, 6\}, \{7, 9, 10, 11, 12, 13\}\) 两个集合。

image

  1. 我们将每一棵树的根当作判断依据,当我们要查询两个元素是否在同一个集合时,可以判断它们是否在同一棵树上,即只要判断它们所在树的根相同与否就可以了,比如下图 \(2, 3\) 有相同的根 \(1\),它们便在一个集合,但是 \(2, 9\) 分别拥有根 \(1, 7\),不在同一个集合。

image

  1. 当我们要合并两个集合时,只要两棵树合并即可,即只要把两棵树的根节点连接起来就可以了。

image

  1. 最开始时,每个元素各为一棵树并且自己就是根。

image

算法优化(路径压缩)

我们发现,如果建出来的树长这样:

image

多次查找非常费时间,因为每次都要从最下面跑到最上面。

因为它们都是一个集合的,不在乎它在集合中的顺序,所以我们可以把树变成这样:

image

即每次查询一个元素在哪一个集合的时候直接把它接在根节点上。

这个可以通过递归实现。

例题1:HDU 1213 How many tables

题目描述

image

思路

认识的人合并为一个集合,最后查找有多少个集合即可。

查询集合数量有两种方法:

方法1:等所有操作进行完成以后,我们可以查询有多少棵树,也就是查找有多少个根;
方法2:我们定义 \(cnt\) 初始值为 \(n\),当合并两个不同的集合时,\(cnt\) 就可以 \(-1\),代表两个集合合并,集合数量少了一个。

代码
#include <bits/stdc++.h>

using namespace std;

const int N = 1010;

int n, m;
int fa[N];

void init() {
    for (int i = 1; i <= n; i++) fa[i] = i;
}

int find(int u) {
    if (u == fa[u]) return u;
    return fa[u] = find(fa[u]);
}

void merge(int a, int b) {
    int fx = find(a), fy = find(b);
    if (fx != fy) fa[fx] = fy;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int T;
    cin >> T;
    while (T--) {
        cin >> n >> m;
        int cnt = n;
        init();
        for (int i = 1; i <= m; i++) {
            int x, y;
            cin >> x >> y;
            if (find(x) != find(y)) cnt--;
            merge(x, y);
        }
        cout << cnt << '\n';
    }

    return 0;
}

第二部分 带权并查集

即为树上的每一条边赋上一个权值,比如边的长度。

相应的,当我们进行路径压缩的优化时,也要不断地更新权值。

比如权值是变得长度时,我们要根据路径压缩的结果对路径权值进行更新:

image

标签:cnt,Set,int,查集,查询,集合,权值,Disjoint
From: https://www.cnblogs.com/PlayWithCPP/p/17549526.html

相关文章

  • 魔法方法之__getitem__(self, key)、__setitem__(self, key, value) 和 __delitem__(s
    1'''2__getitem__(self,key)、__setitem__(self,key,value)和__delitem__(self,key)是Python中的特殊方法,用于定义对对象进行索引操作时的行为。3它们分别用于获取、设置和删除对象中的元素41.__getitem__(self,key):该方法用于通过索引或键来获取对象中的......
  • newcoder61132L <multiset 维护中位数>
    题目中位数多次询问,每次修改数组中一个数,问修改后n个数的中位数思路使用multiset,分别维护数组的较大的\(n/2+1\)个和较小的\(n/2\)个;根据数据范围,或许可用线段树+二分...代码Code#include<iostream>#include<algorithm>#include<vector>#include<cstring>......
  • Solution Set of NFLS SImulations
    在nfls的最后一天,来记录一些似乎有意义的题吧。没有原题(或者我忘了原题)的就简要写下题意,不放原题面了。目录T2(CF1329EDreamoonLovesAA)T1(CF1184D2ParallelUniverses(Hard))T3(CF1434EAConvexGame)T1怪兽(树上MonsterHunting)T2切割T3导弹T1(CF1023GPisc......
  • k8s集群node NotReady处理流程-->kubelet状态error,并伴有报错:kubelet.service has mor
    k8s集群nodeNotReady处理流程-->kubelet状态error//20230712集群有节点NotReadykubelet状态error,并伴有报错:kubelet.servicehasmorethanoneExecStart=setting,whichisonlyallowedforType=oneshotservices.Refusing在此记录一下解决流程解决流程问题定位:使......
  • element 新增修改公用一个弹窗,表单resetFields不生效
    编辑时表单赋值使用 this.$nextTick即可this.$nextTick(()=>{this.formData={id:row.id,taskCode:row.taskCode,fullName:row.fullName,priority:row.priority,taskType:row.taskType,robotId:row.robotId,starTtime......
  • 2023-07-12 vue this.$set设置子组件内的值无效(uniapp+vue)
    前言:怎么说呢,子组件内嵌套了多层对象和数组,业务逻辑也是在子组件内处理,如何修改多层嵌套的对象数组的值?vue提供了一个this.$set方法去改变对应的值,实测在uniapp打包的微信小程序中无法使用该方法,而在Android端则可以,那有没有两全其美的方法?答案是有,在修改深层次的值时可以通过先......
  • mybatis-plus Error attempting to get column 'xxx' from result set.
     报错信息:mybatis-plusErrorattemptingtogetcolumn'xxx'fromresultset. 解决:1、获取数据的实体类中新建了一个有参的构造方法,却没有无参构造方法,使用MyBatis-Plus内置方法进行查询时会报错。解决办法:新建一个无参构造方法。......
  • C++面试八股文:知道std::unordered_set/std::unordered_map吗?
    C++面试八股文:知道std::unordered_set/std::unordered_map吗?某日二师兄参加XXX科技公司的C++工程师开发岗位第27面:面试官:知道std::unordered_set/std::unordered_map吗?二师兄:知道。两者都是C++11引入的新容器,和std::set和std::map功能类似,key唯一,unordered_map的value可变。......
  • 谷歌浏览器Charset扩展程序(解决Google浏览器没有编码的问题)
    较新的谷歌浏览器没有编码这一项,可以选择添加插件的方式,如果无法访问chrome应用商店,请看本文最后的链接下载。将下载好的扩展程序解压,并添加该文件夹。就能看到Charset了。 可以设置了。 下载链接:链接:https://pan.baidu.com/s/1qy53aI6AgCuXUEB0fAb4aQ提取......
  • AT_agc062_c [AGC062C] Mex of Subset Sum 思维妙妙题--zhengjun
    思路比较巧妙。首先排序。考虑目前维护出\(a_{1\simi}\)不能表示的数的集合\(S\)。考虑如何加入\(a_{i+1}\)。如果当前\(<a_i\)的数足够了,直接输出(因为这些数将会一直留在\(S\)中)。记\(sum=\sum\limits_{j=1}^{i}a_j\)。\(a_{i+1}>sum\)\[S'=S\cup[sum+1,a_{i+......