当前位置: 首页 > news >正文

[数据结构]并查集(系统整理版)

基础用法

int p[N];//路径压缩 寻找祖宗节点
int find(int x){if(p[x]!=x) p[x]=find(p[x]);return p[x];
}int main(){
//初始化for(int i=1;i<=n;i++) p[i]=i;
}

合并

void merge(int a,int b){int aa=find(a),bb=find(bb);if(aa!=bb){p[aa]=bb;}
}

查询是否联通

bool is_connected(int a,int b){int aa=find(a),bb=find(bb);if(aa==bb) return 1;else return 0;
}

如何维护联通块数量

初始化cnt为元素个数n
每次合并时 cnt–
最后cnt即为最后的连通块个数

int cnt=n;
void merge(int a,int b){int aa=find(a),bb=find(bb);if(aa!=bb){p[aa]=bb;}cnt--;
}

如何维护每个连通块的元素个数

维护一个size数组s 初始化为1
for(int i=1;i<=n;i++) s[i]=1;

  • size数组不能定义为int size[N]size会与cpp内部的关键字混淆
int s[N];
int cnt=n;void merge(int u,int v){int uu=find(u),vv=find(v);if(uu!=vv){if(s[uu]>s[vv]){p[vv]=uu;s[uu]+=s[vv];}else{p[uu]=vv;s[vv]+=s[uu];}cnt--;}
}

按秩合并

每次合并把元素少的连通块合并到元素多的去
因为并查集类似树形结构
这样合并能时树的高度增长相对少
减少路径压缩次数 提高查询效率

如何像STL一样使用并查集

借鉴了LeetCode的并查集模板

基础版

#include<bits/stdc++.h>
using namespace std;class UnionFind{
private:vector<int>p,s;
public:int cnt=0;UnionFind(int n): p(n+1),s(n+1,1){//多开一个空间 同时适用于0-based&1-basediota(p.begin(),p.end(),0);cnt=n;}int find(int x){if(p[x]!=x) p[x]=find(p[x]);return p[x];}void merge(int u,int v){int uu=find(u),vv=find(v);if(uu!=vv){if(s[uu]>s[vv]){p[vv]=uu;s[uu]+=s[vv];roots.erase(vv);}else {p[uu]=vv;s[vv]+=s[uu];roots.erase(uu);}cnt--;}}bool is_connected(int u,int v){return find(u)==find(v);}int size(int x){return s[x];}	};

维护每个连通块的根节点

不需要维护cnt了 根节点的数量就是连通块的数量

#include<bits/stdc++.h>
using namespace std;class UnionFind{
private:vector<int>p,s;unordered_set<int>roots;//新增
public:UnionFind(int n): p(n+1),s(n+1,1){//多开一个空间 同时适用于0-based&1-basediota(p.begin(),p.end(),0);for(int i=0;i<n;i++){//如果1-based就改成i->[1,n]roots.insert(i);}}int find(int x){if(p[x]!=x) p[x]=find(p[x]);return p[x];}void merge(int u,int v){int uu=find(u),vv=find(v);if(uu!=vv){if(s[uu]>s[vv]){p[vv]=uu;s[uu]+=s[vv];roots.erase(vv);}else {p[uu]=vv;s[vv]+=s[uu];roots.erase(uu);}}}bool is_connected(int u,int v){return find(u)==find(v);}int size(int x){return s[x];}	vector<int>get_roots(){return vector<int>(roots.begin(),roots.end());}int get_cnt(){return roots.size();}
};

维护每个连通块内的边的数量

#include<bits/stdc++.h>
using namespace std;class UnionFind{
private:vector<int>p,s,ecnt;//ecnt[i]表示以find(i)为根的连通块的边数unordered_set<int>roots;
public:UnionFind(int n): p(n+1),s(n+1,1),ecnt(n+1,0){//多开一个空间 同时适用于0-based&1-basediota(p.begin(),p.end(),0);for(int i=0;i<n;i++){//如果1-based就改成i->[1,n]roots.insert(i);}}int find(int x){if(p[x]!=x) p[x]=find(p[x]);return p[x];}void merge(int u,int v){int uu=find(u),vv=find(v);if(uu!=vv){if(s[uu]>s[vv]){p[vv]=uu;s[uu]+=s[vv];ecnt[uu]+=ecnt[vv]+1;roots.erase(vv);}else {p[uu]=vv;s[vv]+=s[uu];ecnt[vv]+=ecnt[uu]+1;roots.erase(uu);}}else{ecnt[uu]++;//已经联通了也要加边数}}bool is_connected(int u,int v){return find(u)==find(v);}int size(int x){return s[x];}	int get_ecnt(int x){return ecnt[find(x)];}    vector<int>get_roots(){return vector<int>(roots.begin(),roots.end());}int get_cnt(){return roots.size();}
};

http://www.mrgr.cn/news/96538.html

相关文章:

  • Pinia的安装,使用,与情景教学
  • 大模型评测框架evalscope、openCompass
  • 【论文阅读】Co2l: Contrastive continual learning
  • 内网服务器无法通过公网地址访问映射到公网的内网服务
  • strcpy和strncpy和strcat和strncat和strstr和strtok函数使用及实现
  • MIPS-32架构(寄存器堆,指令系统,运算器)
  • 第三次作业
  • Epub转PDF软件Calibre电子书管理软件
  • LLM实践(二)——基于llama-factory的模型微调
  • mybatis里in关键字拼接id问题
  • GOF23种设计模式
  • 从Web到桌面:深入解析Electron的技术架构与应用实践
  • RK3588,V4l2 读取Gmsl相机, Rga yuv422转换rgb (dma), 实现零拷贝
  • Docker实现MySQL主从复制配置【简易版】
  • AutoDIR: Automatic All-in-One Image Restoration with Latent Diffusion 论文阅读 ECCV
  • UE5 学习笔记 FPS游戏制作30 显示击杀信息 水平框 UI模板(预制体)
  • .js项目编译成.exe程序(交叉编译全过程整理)
  • Docker使用ubuntu
  • 浅析车规芯片软错误防护加固的重要性
  • 设计模式之适配器模式(二):STL适配器