<泛> 并查集
最近写这些东西呢,主要是整理一下知识,自己写一遍,看看还是不是我的。
原理与实践相结合,缺一不可
背景
有时候,给你一张很复杂的关系网络图,如果关系具有传递性,那么,我们该如何处理这些关系集合。
一个很简单的例子就是,大学里面有很多人,如果我们获取到他们两两之间的相识关系,如果相识关系具备可传递性,那么,很多信息需要求解:
·任意两个人拉出来,他们是否认识呢,如果群体很庞大,我们该如何求解该问题·
·所有这些人总共可以分为多少个集合呢,怎么求解呢
等等等等
我们今天用一个数据结构来解决这些问题,或者说,用并查集来维护这些信息
思想
我们用树结构来实现,如果两个人认识,我们就创建两个树结点代表之,且任指一个结点作为另一个结点的父节点,我们把所有的两两关系均如此做,就可以得到一棵关系树。
如: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 思路:并查集处理出哪几堆袜子是同一颜色的,对于每堆袜子求出出现最多颜色的次数,用这堆袜子的数目减去该值即为 ...
随机推荐
- 最大团 HDU-1530
传送门: 洛谷 Vjudge (题目略有不同) 题目描述 • 给定一个图 tt = (V, E) • 求一个点集 S ,使得对于任意 x ≠ y ∈ S ,x 和 y 都有一条边 • |V | ...
- JavaScript的基本概念
主要内容: 语法 数据类型 流控制语句 理解函数 ECMA-262描述了JavaScript语法等基本概念.目前,ECMA-262第3版中定义的ECMAScript是各个浏览器实现最多的版本.所以主要 ...
- Spring4笔记3--Bean的装配
Bean的装配: Bean 的装配,即 Bean 对象的创建.容器根据代码要求创建 Bean 对象后再传递给代码的过程,称为 Bean 的装配. 1. 创建Bean对象的方式: 1. 通过 getBe ...
- excel导入时候日期格式转成date
最近在做导入的时候发现,excel中设置数值格式是不能有日期的那些符号出现的,/ - : 之类的,否则就会变成数字到了java后台,设置成日期,比如 yyyy-mm-dd 到了后台也是数字,即距离19 ...
- Linux修改主机名【转】
一.永久修改修改/etc/sysconfig/network,在里面指定主机名称HOSTNAME=然后执行命令hostname 主机名这个时候可以注销一下系统,再重登录之后就行了. 或者修改/etc/ ...
- C#之WinForm基础 新建一个不可编辑的comboBox
慈心积善融学习,技术愿为有情学.善心速造多好事,前人栽树后乘凉.我今于此写经验,愿见文者得启发. 1.拉控件 2.添加可选数据 3.改变基本样式 4.效果图 C#优秀,值得学习.Winform,WPF ...
- MVVM模式的 数据绑定
数据绑定要达到的效果 数据绑定要达到什么效果呢,就是在界面中绑定了数据源之后,数据在界面上的修改能反映到绑定源,同时绑定源的修改也能反映到界面上.从界面反映到绑定的数据源是很容易理解的,因为在绑定过程 ...
- C 语言问题
1. 如何生成 "半全局变量", 就是那种只能被部分源文件中的部分函数访问变量? 答: 这在C语言中办不到. 如果不能或不方便在一个源文件中放下所有的函数, 那么有三种的解决方案 ...
- js写的一些通用方法
Js获取当前浏览器支持的transform兼容写法 // 获取当前浏览器支持的transform兼容写法 function getTransfrom() { var transform = '', / ...
- PHP SPL使用方法 自动加载和迭代器
SPL,PHP 标准库(Standard PHP Library) ,此从 PHP 5.0 起内置的组件和接口,并且从 PHP5.3 已逐渐的成熟.SPL 其实在所有的 PHP5 开发环境中被内置,同 ...