<泛> 并查集
最近写这些东西呢,主要是整理一下知识,自己写一遍,看看还是不是我的。
原理与实践相结合,缺一不可
背景
有时候,给你一张很复杂的关系网络图,如果关系具有传递性,那么,我们该如何处理这些关系集合。
一个很简单的例子就是,大学里面有很多人,如果我们获取到他们两两之间的相识关系,如果相识关系具备可传递性,那么,很多信息需要求解:
·任意两个人拉出来,他们是否认识呢,如果群体很庞大,我们该如何求解该问题·
·所有这些人总共可以分为多少个集合呢,怎么求解呢
等等等等
我们今天用一个数据结构来解决这些问题,或者说,用并查集来维护这些信息
思想
我们用树结构来实现,如果两个人认识,我们就创建两个树结点代表之,且任指一个结点作为另一个结点的父节点,我们把所有的两两关系均如此做,就可以得到一棵关系树。
如:r 认识 z,z 认识 q,那么r 可以通过 z 认识 q,在树结构上同样如此,树表示为一棵单支树,r——z——q
但是,如果数量很大的话,这棵树将会有很多层,如果要解决第一个问题,我们还需要遍历整棵树才能得到答案,还是很费时间
那么我们采用路径压缩的方法来解决,即: r
/ \
z q
我们把q也挂在z的父亲下面,所有的结点都如此做,如果两个人所指向的根(父)结点是同一个,那么两个人在一个集合中,此查询复杂度为O(1)
我们来解决第二个问题,一共可以构成多少个关系网(集合),我们最开始设置每个节点的根节点为自己,经过上述处理后,我们只需要检查一下有多少个节点的根节点为自己,说明就有多少张关系网。 此查询复杂度为: O(n)
泛型代码:
//Union_Find.h #pragma once
#include <map> template<typename value_type>
class Union_Find
{
public:
Union_Find();
value_type find(const value_type&);
void unite(value_type, value_type);
int set_cnt()const; //总共的构成的集合个数
bool same(const value_type&, const value_type&); private:
void _clear();
void _init(const value_type&); private:
std::map<value_type, value_type> _parent;
std::map<value_type, int> _rank; //记录树的高度
}; template<typename value_type>
Union_Find<value_type>::Union_Find()
{
_clear();
} template<typename value_type>
void Union_Find<value_type>::_clear()
{
_parent.clear();
_rank.clear();
} template<typename value_type>
value_type Union_Find<value_type>::find(const value_type& item)
{
if (_parent[item] == item) return item;
return _parent[item] = find(_parent[item]); //![1] 顺便 实现 路径压缩
} template<typename value_type>
void Union_Find<value_type>::unite(value_type lhs, value_type rhs)
{
_init(lhs), _init(rhs); lhs = _parent[lhs];
rhs = _parent[rhs];
if (lhs == rhs)return; //![2] 合并两棵树,其实可以直接把右挂在左树上,或反之,但是为了使合并后的整棵树的高度最低,我们选择将rank小的向rank大的连边
//[1]和[2] 的双重优化之下,我们的并查集效率就会非常高了,可以达到O(α(n))的时间复杂度α(n)为Ackermann(阿克曼)函数的反函数,效率比O(log(n))还快
if (_rank[lhs] < _rank[rhs]) _parent[lhs] = rhs;
else
{
_parent[rhs] = lhs;
if (_rank[lhs] == _rank[rhs]) _rank[lhs]++;
}
} template<typename value_type>
void Union_Find<value_type>::_init(const value_type& item)
{
if (_parent[item] == value_type())_parent[item] = item; //如果没有映射,设为自己
} template<typename value_type>
bool Union_Find<value_type>::same(const value_type& lhs, const value_type& rhs)
{
return find(lhs) == find(rhs);
} template<typename value_type>
int Union_Find<value_type>::set_cnt()const
{
int cnt{ };
for (auto it : _parent)
if (it.first == it.second)cnt++;
return cnt;
}
测试与使用:
#include"E:\数据结构\Union_Find.h"
#include <iostream>
#include <string>
using namespace std; int main()
{
Union_Find<string> Ufind;
string lhs, rhs;
cout << "请输入关系网络图:" << endl;
while (cin >> lhs >> rhs, lhs != "null")
Ufind.unite(lhs, rhs); while (cin >> lhs >> rhs, lhs != "null")
if (Ufind.same(lhs, rhs))cout << lhs << " 和 " << rhs << " 认识" << endl;
else cout << lhs << " 和 " << rhs << " 不认识" << endl;
cout << endl << "该程序一共有" << Ufind.set_cnt() << "关系圈子" << endl;
}
结果

感谢您的阅读,生活愉快~
<泛> 并查集的更多相关文章
- luoguP3224 [HNOI2012]永无乡【线段树,并查集】
洞庭青草,近中秋,更无一点风色.玉鉴琼田三万顷,着我扁舟一叶.素月分辉,明河共影,表里俱澄澈.悠然心会,妙处难与君说. 应念岭表经年,孤光自照,肝胆皆冰雪.短发萧骚襟袖冷,稳泛沧溟空阔.尽挹西江,细斟 ...
- BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]
4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...
- 关押罪犯 and 食物链(并查集)
题目描述 S 城现有两座监狱,一共关押着N 名罪犯,编号分别为1~N.他们之间的关系自然也极不和谐.很多罪犯之间甚至积怨已久,如果客观条件具备则随时可能爆发冲突.我们用"怨气值"( ...
- 图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用
图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 ...
- bzoj1854--并查集
这题有一种神奇的并查集做法. 将每种属性作为一个点,每种装备作为一条边,则可以得到如下结论: 1.如果一个有n个点的连通块有n-1条边,则我们可以满足这个连通块的n-1个点. 2.如果一个有n个点的连 ...
- [bzoj3673][可持久化并查集 by zky] (rope(可持久化数组)+并查集=可持久化并查集)
Description n个集合 m个操作 操作: 1 a b 合并a,b所在集合 2 k 回到第k次操作之后的状态(查询算作操作) 3 a b 询问a,b是否属于同一集合,是则输出1否则输出0 0& ...
- [bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)
Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...
- 【BZOJ-3673&3674】可持久化并查集 可持久化线段树 + 并查集
3673: 可持久化并查集 by zky Time Limit: 5 Sec Memory Limit: 128 MBSubmit: 1878 Solved: 846[Submit][Status ...
- Codeforces 731C Socks 并查集
题目:http://codeforces.com/contest/731/problem/C 思路:并查集处理出哪几堆袜子是同一颜色的,对于每堆袜子求出出现最多颜色的次数,用这堆袜子的数目减去该值即为 ...
随机推荐
- Java开发者应该列入年度计划的5件事
本文写了我今年计划要做的5件事.为了能跟踪计划执行的进度,就把这些事都列了出来.我觉得这些事对其它Java开发者而言也是不错的参考方向. 1.开发一个应用,通过Java来操作一种NoSQL数据库实现存 ...
- 最长递增子序列(LIS)(转)
最长递增子序列(LIS) 本博文转自作者:Yx.Ac 文章来源:勇幸|Thinking (http://www.ahathinking.com) --- 最长递增子序列又叫做最长上升子序列 ...
- ETL测试基本知识
转载自: https://www.cnblogs.com/clarke157/p/6383024.html 一.ETL测试的重要性: ETL(Extract-Transform-Load的缩写,即数据 ...
- HDU 2063 过山车 二分匹配
解题报告:有m个女生和n个男生要结成伴坐过山车,每个女生都有几个自己想选择的男生,然后要你确定最多能组成多少对组合. 最裸的一个二分匹配,这是我第一次写二分匹配,给我最大的感受就是看那些人讲的匈牙利算 ...
- Windows执行命令与下载文件总结
1.前言 在渗透或是病毒分析总是会遇到很多千奇百怪的下载文件和执行命令的方法. 2.实现方式 2.1.Powershell win2003.winXP不支持 $client = new-object ...
- npm 安装 electron 超时
由于某些不可描述的原因,俺的某个小项目要用客户端桌面应用,后台那还是 php 了.经广大的群友指导,发现了 Electron 这个项目.它可以用 html, css, javascript 构建跨平台 ...
- 001_Mac键盘图标与对应快捷按键标志汇总
Mac键盘图标与对应快捷按键 ⌘——Command () win键 ⌃ ——Control ctrl键 ⌥——Option (alt) ⇧——Shift ⇪——Caps Lock fn——功能键就是 ...
- js API
从基础知识JS-web-API js基础知识:ECMA 262标准 js-web-API: w3c标准 W3c标准中关于js的规定有 DOM操作.BOM操作.事件绑定.ajax请求(包括http协议) ...
- Python匿名函数详解
python 使用 lambda 来创建匿名函数. lambda这个名称来自于LISP,而LISP则是从lambda calculus(一种符号逻辑形式)取这个名称的. 在Python中,lambda ...
- 【CF767C】Garland
传送门啦 分析: 这个题我是看着翻译做的,感觉不是很难,很普通的一个树形dp 题目大意: 在一棵树上分离出三个子树,使这三个子树的点权和相等. 明确题目意思这个题就简单多了吧. 我们会发现每一棵子树的 ...