<泛> 并查集
最近写这些东西呢,主要是整理一下知识,自己写一遍,看看还是不是我的。
原理与实践相结合,缺一不可
背景
有时候,给你一张很复杂的关系网络图,如果关系具有传递性,那么,我们该如何处理这些关系集合。
一个很简单的例子就是,大学里面有很多人,如果我们获取到他们两两之间的相识关系,如果相识关系具备可传递性,那么,很多信息需要求解:
·任意两个人拉出来,他们是否认识呢,如果群体很庞大,我们该如何求解该问题·
·所有这些人总共可以分为多少个集合呢,怎么求解呢
等等等等
我们今天用一个数据结构来解决这些问题,或者说,用并查集来维护这些信息
思想
我们用树结构来实现,如果两个人认识,我们就创建两个树结点代表之,且任指一个结点作为另一个结点的父节点,我们把所有的两两关系均如此做,就可以得到一棵关系树。
如: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 思路:并查集处理出哪几堆袜子是同一颜色的,对于每堆袜子求出出现最多颜色的次数,用这堆袜子的数目减去该值即为 ...
随机推荐
- 大数据测试之ETL测试工具和面试常见的问题及答案
转载自: http://www.51testing.com/html/87/n-3722487.html 概述 商业信息和数据对于任何一个企业而言都是至关重要的.现在很多公司都投入了大量的人力.资金和 ...
- Anaconda+django写出第一个web app(二)
今天开始建立App中的第一个Model,命名为Tutorial. Model的定义在main文件夹下的models.py中通过类进行,我们希望Tutorial这个model包含三个属性:标题.内容和发 ...
- 利用Object.defineProperty 简化 Chrome插件本地存储操作
通常谷歌插件本地存储写法很别扭☹,如 chrome.storage.sync.get(null,function(data){ //todo console.log(data); }); 如果get ...
- 【方法】jQuery无插件实现 鼠标拖动切换图片/内容 功能
前言 我就想随便叨逼叨几句,爱看就看几句,不爱看就直接跳过看正文就好啦~ 这个方法是仿写页面时我自己研究出来,可能有比我更简单的方法. 但我不管,因为我没查我不知道,我就觉得我的最好啦,耶耶耶~ 效果 ...
- 使用Picker的时候,让input输入框使用焦点,手机键盘不弹出
$("#address").click(function(){ document.activeElement.blur(); })
- 64_t7
texlive-ulqda-bin-svn13663.0-33.20160520.fc26.2..> 24-May-2017 15:57 33102 texlive-ulqda-doc-svn2 ...
- 二十一、springboot之定制URL匹配规则(项目中遇到的问题:get方式传参,带有小数点,被忽略)
一.问题描述: get方式传参,在传送价格,积分时(带有小数点),debug后台微服务接受到的参数,却不带小数点,如:price是0.55,后台接受后却是0 二.解决 在WebConfiguratio ...
- js中图片获取src的正则
链接: JavaScript 正则表达式:http://www.runoob.com/js/js-regexp.html js正则匹配出所有图片及图片地址src的方法:http://www.jb51. ...
- spring boot jpa 多数据源配置
在实际项目中往往会使用2个数据源,这个时候就需要做额外的配置了.下面的配置在2.0.1.RELEASE 测试通过 1.配置文件 配置两个数据源 spring.datasource.url=jdbc:m ...
- NLP里面好的学习资料
别人推荐的网址: http://ruder.io/deep-learning-nlp-best-practices/index.html#wordembeddings