并查集
作者:互联网
1 //-----并查集的初始化----- 2 3 //一开始有n个元素,互相独立,则构成了n个集合,每个集合的代表元素就是它本身 4 5 const int maxn = 100010; 6 7 int fa[maxn + 1]; //fa数组记录每个元素由谁代表 8 int sz[maxn + 1]; //sz数组记录每个集合的元素个数 9 int dep[maxn + 1]; //dep数组记录每个集合的树深度 10 11 inline void Initialize(int n){ 12 for (int i = 1;i <= n;i++){ //一共有n个点 13 fa[i] = i; //把代表元素设置为自己 14 sz[i] = dep[i] = 1; //一开始的深度就是1,子树大小也是1,因为只有自己孤零零的一个元素 15 } 16 return; 17 } 18 19 //-----集合合并----- 20 21 int Findset(int x){ //这个是用来找代表元素的函数,递归找 22 if (fa[x] == x){ 23 return x; 24 } 25 return Findset(fa[x]); 26 } 27 28 void Union(int x, int y){ 29 int fx = Findset(x); 30 int fy = Findset(y); 31 if (fx == fy){ //如果发现是一家子的,那得了直接完事儿了 32 return; 33 } 34 fa[fx] = fy; //否则我们就搞个强扭的瓜,扭到一起去 反过来写也是可以 35 return; 36 } 37 38 //-----路径压缩----- 39 40 //大致思路就是在查询的操作过程中,把沿途经过的每一个节点的fa都设置为集合的代表元 41 42 int QuicklyFindset(int x){ 43 if (x == fa[x]){ //如果就是代表元素就直接返回咯 44 return x; 45 } 46 fa[x] = QuicklyFindset(fa[x]); //在不是的情况下每一次都设置一遍 47 return fa[x]; 48 } 49 50 /* 51 上述代码简写版: 52 int QuicklyFindset(int x){ 53 return x == fa[x] ? x : (fa[x] == QuicklyFindset(fa[x])); 54 } 55 */ 56 57 //-----启发式合并----- 58 59 //log的复杂度 60 61 //大体思路:在合并集合的过程中,我们尽量选择包含元素个数少的集合,将它合并到另一个集合之中去,使要改变代表元的元素尽可能的少 62 //这种将较小的集合合并到较大的集合之中的方法被称为 启发式合并,在其他的数据结构中也很常见 63 64 void HeuristicUnion(int x, int y){ 65 int fx = Findset(x); 66 int fy = Findset(y); 67 if (fx == fy){ 68 return; 69 } 70 if (sz[fx] > sz[fy]){ 71 swap(fx, fy); //确定谁是骡子谁是马 72 } 73 fa[fx] = fy; 74 sz[fy] += sz[fx]; //子树的大小也要加起来 75 return; 76 } 77 78 //-----按深度合并----- 79 80 //log的复杂度 81 82 //大体思路:每一次合并的过程中,将深度较小的集合合并到深度较大的一方去,并更新一下新集合的深度 83 //值得一提的是,在路径压缩的时候,可能会破坏维护的深度值,但其实整体算法的复杂度不会变差 84 85 void DeepUnion(int x, int y){ 86 int fx = Findset(x); 87 int fy = Findset(y); 88 if (fx == fy){ 89 return; 90 } 91 if (dep[fx] > dep[fy]){ 92 swap(fx, fy); 93 } 94 fa[fx] = fy; 95 if (dep[fx] == dep[fy]){ //只有两棵树深度相等的时候才会更新 96 dep[fy]++; 97 } 98 return; 99 }
标签:sz,fx,int,fy,查集,dep,深度 来源: https://www.cnblogs.com/Conqueror712/p/16459497.html