<泛> 并查集
最近写这些东西呢,主要是整理一下知识,自己写一遍,看看还是不是我的。
原理与实践相结合,缺一不可
背景
有时候,给你一张很复杂的关系网络图,如果关系具有传递性,那么,我们该如何处理这些关系集合。
一个很简单的例子就是,大学里面有很多人,如果我们获取到他们两两之间的相识关系,如果相识关系具备可传递性,那么,很多信息需要求解:
·任意两个人拉出来,他们是否认识呢,如果群体很庞大,我们该如何求解该问题·
·所有这些人总共可以分为多少个集合呢,怎么求解呢
等等等等
我们今天用一个数据结构来解决这些问题,或者说,用并查集来维护这些信息
思想
我们用树结构来实现,如果两个人认识,我们就创建两个树结点代表之,且任指一个结点作为另一个结点的父节点,我们把所有的两两关系均如此做,就可以得到一棵关系树。
如: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 思路:并查集处理出哪几堆袜子是同一颜色的,对于每堆袜子求出出现最多颜色的次数,用这堆袜子的数目减去该值即为 ...
随机推荐
- Presto通过RESTful接口新增Connector
在实际使用Presto的过程中,经常会有以下的一些需求. 添加一个新的Catalog 对不再使用的Catalog希望把它删除 修改某个Catalog的参数 但在Presto中如果进行上述的修改,需要重 ...
- 20155210潘滢昊 2016-2017-2 《Java程序设计》第5周学习总结
20155210 2016-2017-2 <Java程序设计>第5周学习总结 教材学习内容总结 try with resources 关闭多个资源时用分号分隔 java.lang.Auto ...
- thinkphp 带条件分页查询
thinkphp 带条件分页查询:form表单传值时候,method='get'. 用 get 传值
- (转载) 天梯赛 L2-018. 多项式A除以B
题目链接 题目描述 这仍然是一道关于A/B的题,只不过A和B都换成了多项式.你需要计算两个多项式相除的商Q和余R,其中R的阶数必须小于B的阶数. 输入格式: 输入分两行,每行给出一个非零多项式,先给出 ...
- C++的各种初始化方式
C++小实验测试:下面程序中main函数里a.a和b.b的输出值是多少? #include <iostream> struct foo { foo() = default; int a; ...
- C++ Qt多线程 TcpSocket服务器实例
服务器: incomming incomming.pro #------------------------------------------------- # # Project created ...
- Win7下VS2010不能链接问题
装了2012准备学VC++窗体开发,然后发现手边只有VS2010的教程,于是卸掉VS2012改装VS2010,结果发现不管写啥,链接时都报错“error Link1123 转到coff期间失败”. 于 ...
- MongoDB以Windows Service运行
以Administrator身份打开CMD并输入以下命令 cd D:\Developer\MongoDB\mongodb-win32-x86_64-2.4.6\binD:mongod --logpat ...
- linux挂载光盘
1.找到光盘的位置 ls -l /dev |grep cdrom mount /dev/sr0 /mnt [root@node2 /]# ls -l /dev |grep cdrom lrwxrwx ...
- 莫烦课程Batch Normalization 批标准化
for i in range(N_HIDDEN): # build hidden layers and BN layers input_size = 1 if i == 0 else 10 fc = ...