并查集

给并查集融入武侠元素——看完故事就会了

随声附和 提交于 2019-12-26 00:44:02
这篇博客是转载来自一位大神,用武侠小说元素去介绍并查集的知识,关于那位大神简单有趣 感兴趣的点这里 例子就是杭电上的畅通工程: http://acm.hdu.edu.cn/showproblem.php?pid=1232 首先在地图上给你若干个城镇,这些城镇都可以看作点,然后告诉你哪些对城镇之间是有道路直接相连的。最后要解决的是整幅图的连通性问题。比如随意给你两个点,让你判断它们是否连通,或者问你整幅图一共有几个连通分支,也就是被分成了几个互相独立的块。像畅通工程这题,问还需要修几条路,实质就是求有几个连通分支。 如果是1个连通分支,说明整幅图上的点都连起来了,不用再修路了;如果是2个连通分支,则只要再修1条路,从两个分支中各选一个点,把它们连起来,那么所有的点都是连起来的了;如果是3个连通分支,则只要再修两条路…… 以下面这组数据输入数据来说明 4 2 1 3 4 3 第一行告诉你,一共有4个点,2条路。下面两行告诉你,1、3之间有条路,4、3之间有条路。那么整幅图就被分成了1-3-4和2两部分。只要再加一条路,把2和其他任意一个点连起来,畅通工程就实现了,那么这个这组数据的输出结果就是1。好了,现在编程实现这个功能吧,城镇有几百个,路有不知道多少条,而且可能有回路。 这可如何是好? 我以前也不会呀,自从用了并查集之后,嗨,效果还真好!我们全家都用它!

并查集(Union-Find)

僤鯓⒐⒋嵵緔 提交于 2019-12-24 16:49:27
Source: PAT A1114 Family Property (25 分) Description: This time, you are supposed to help us collect the data for family-owned property. Given each person's family members, and the estate(房产)info under his/her own name, we need to know the size of each family, and the average area and number of sets of their real estate. Input Specification: Each input file contains one test case. For each case, the first line gives a positive integer N ( ≤). Then N lines follow, each gives the infomation of a person who owns estate in the format: ID Father Mother k C h i l d ​ 1 ​​ ⋯ C h i l d ​ k ​​ M ​ e s

可持久化并查集

断了今生、忘了曾经 提交于 2019-12-24 06:13:10
可持久化并查集 简单来说就是两颗主席树 一颗维护 父亲节点是谁 一颗维护 深度 为什么要维护深度? 降低时间复杂度 并查集如果不优化的查询的话是这样: int findx ( int x ) { return x == fa [ x ] ? x : findx ( fa [ x ] ) ; } void hebing ( int x , int y ) { int xx = findx ( x ) ; int yy = findx ( y ) ; if ( xx != yy ) { fa [ xx ] = yy ; } } 这个时间复杂度最坏可以到达O(n) 的 优化一: 路径压缩是这样: 基本是常数复杂度? void hebing ( int x , int y ) { int xx = findx ( x ) ; int yy = findx ( y ) ; if ( xx != yy ) { fa [ xx ] = yy ; } } int findx ( int x ) { return x == fa [ x ] ? x : fa [ x ] = findx ( fa [ x ] ) ; } 但是可持久化的话这样每压缩一次就算一个状态? 可能会MLE? 优化二: 按秩合并: 就是按照他的这个树的大小来合并,把小的树的根节点连到大的树的根节点上面这样可以使树尽量低

一般图最大匹配——带花树

不打扰是莪最后的温柔 提交于 2019-12-24 02:49:17
所谓花,就是如下图所示的一个奇环: 本文中粗边代表现在的匹配边,细边代表该点的前驱(后文会讲解前驱是什么,现在只需要知道每个点和它的前驱在原图中一定是有边的)。 如图所示,一朵包含 \(2k+1\) 个点的花一定至多包含 \(k\) 条匹配边,于是总会剩下一个未匹配的点,上图中即为 \(1\) 号点。 那么我们可以发现,如果有另外一个点想要与花中的某个点 \(v\) 匹配,那么有两种情况:1、 \(v\) 是未匹配的点(即1号点),那么直接与 \(v\) 匹配即可。2、 \(v\) 是已经匹配的点,这时只要将花中的匹配状况修改,使得 \(v\) 变成未匹配的那个点即可。 综上所述,只要花中的点没有向外匹配,我们总是可以使得外部的一个点和花中任意一个点匹配,因此花的性质和点其实很相似。我们将花缩成一个点来处理,就可以解决出现奇环的问题。以上思想就是带花树算法的核心。 ==================总之分割一下好了================== 带花树算法的过程其实和 \(bfs\) 版本的匈牙利是很相似的,都是找出一个交错树,交错树可能长这样(注意每个蓝色点可能有多个橙色儿子,但是每个橙色点只能有一个蓝色儿子): 其中1号点就是我们尝试增广的节点,在这里我们给每一个节点一个 \(type\) 值,若该点不在交错树中,它的 \(type\) 值为 \(0\) ,否则为 \

1526朋友圈问题--并查集练习

馋奶兔 提交于 2019-12-23 03:14:30
题目描述: 假如已知有n个人和m对好友关系(存于数字r)。如果两个人是直接或间接的好友(好友的好友的好友...),则认为他们属于同一个朋友圈,请写程序求出这n个人里一共有多少个朋友圈。 假如:n = 5 , m = 3 , r = {{1 , 2} , {2 , 3} , {4 , 5}},表示有5个人,1和2是好友,2和3是好友,4和5是好友,则1、2、3属于一个朋友圈,4、5属于另一个朋友圈,结果为2个朋友圈。 输入: 输入包含多个测试用例,每个测试用例的第一行包含两个正整数 n、m,1=<n,m<=100000。接下来有m行,每行分别输入两个人的编号f,t(1=<f,t<=n),表示f和t是好友。 当n为0时,输入结束,该用例不被处理。 输出: 对应每个测试用例,输出在这n个人里一共有多少个朋友圈。 样例输入: 5 3 1 2 2 3 4 5 3 3 1 2 1 3 2 3 0 样例输出: 2 1 #include <iostream> #include <cstdio> #include <cstring> using namespace std; int f[10000],n,m,a,b; void init() //初始化 { for(int i=0; i<n; i++) f[i] = i; } int find(int x)//找上级 { return f[x]==x

并查集--QuickFind实现

风流意气都作罢 提交于 2019-12-23 01:28:06
1 并查集的意义 判断连通性问题 初始化每个元素都是不同集合 判断两个点是否连通,查看是否在同一个集合中即可 2 QuickFindUF实现 顾名思义,查询非常快,用数组来存储,每个索引对应的是集合的编号 /** * @author Created by qiyei2015 on 2019/12/11. * @version: 1.0 * @email: 1273482124@qq.com * @description: 快速查询的并查集 * 用数组来存储,每个索引对应的是集合的编号 */ public class QuickFindUF implements UF{ /** * 元素集合 */ private int[] id; public QuickFindUF(int size) { id = new int[size]; //分别属于不同的集合 for (int i = 0 ;i < id.length; i++){ id[i] = i; } } @Override public int size() { return id.length; } /** * 时间复杂度O(n) * @param p * @param q */ @Override public void union(int p, int q) { int idP = find(p); int idQ =

Codeforces Round #603 (Div. 2)

别来无恙 提交于 2019-12-23 00:38:10
Codeforces Round #603 (Div. 2) D. Secret Passwords 字符串的并查集 题意: 现在你有n个密码,但里面有些密码是等价的 等价的定义是: 假设存在一个字母x,在a和b字符串都出现过,那么a字符串和b字符串就是等价的。 假设a字符串和c字符串等价,b和c字符串等价,那么a和b也等价。 问你最少掌握多少个密码,就能掌握所有密码了 解题方法:并查集裸题,把每一个字符串的里字符用并查集维护,后面看有几个集合就行了。跟每次输入一个数字其实大体上差不多。实际上就是对二十六个字母使用并查集进行合并;但是要注意区分没有出现过的字母; AC代码: # include <iostream> # include <cstdio> # include <cstring> # include <stack> # include <queue> # include <set> # include <map> # include <vector> # include <list> # include <cmath> # include <algorithm> # define lson node<<1,st,mid # define rson node<<1|1,mid+1,ed # define mem(a,x) memset(a,x,sizeof(a)) #

【JZOJ】【并查集】设备塔

╄→гoц情女王★ 提交于 2019-12-21 12:03:57
D e s c r i p t i o n Description D e s c r i p t i o n 为了封印辉之环,古代塞姆利亚大陆的人民在异空间中建造了一座设备塔。 简单的说,这座设备塔是一个漂浮在异空间中的圆柱体,圆柱体两头的圆是计算核心,而侧面则是 传输信息所用的数据通道,划分成N *m 个区块。 然而,随着工作的继续进行,他们希望把侧面的一部分区块也改造成其他模块。然而,任何时候都 必须保证存在一条数据通道,能从圆柱体的一端通向另一端。 由于无法使用辉之环掌控下的计算系统,他们寻求你的帮助来解决这个问题。他们将逐个输入想要 改造的区域,而你则执行所有可行的改造并忽略可能导致数据中断的改造。 I n p u t Input I n p u t 第一行,包含两个整数N;M;K,表示侧面的长和宽,以及操作数。 接下来K 行,每行包含三个整数xi; yi,表示操作的区块的坐标。(0<=y=<M) 数据保证不会对已经操作成功的区块进行操作。 O u t p u t Output O u t p u t 输出一行,表示有多少个操作可以被执行。 S a m p l e I n p u t SampleInput S a m p l e I n p u t 3 4 9 2 2 3 2 2 3 3 4 3 1 1 3 2 1 1 1 1 4 S a m p l e O u t p

【algo&ds】【pat】5.并查集及其应用

本秂侑毒 提交于 2019-12-20 00:44:45
1.并查集的定义 在计算机科学中, 并查集 是一种树型的数据结构,用于 处理一些不交集(Disjoint Sets)的合并及查询问题 。有一个联合-查找算法(union-find algorithm)定义了两个用于此数据结构的操作: Find :确定元素属于哪一个子集。 Union :将两个子集合并成同一个集合。 MakeSet ,用于建立单元素集合。 为了更加精确的定义这些方法,需要定义 如何表示集合 。一种常用的策略是为每个集合选定一个固定的元素,称为代表,以表示整个集合。接着, Find(x) 返回 x 所属集合的代表,而 Union 使用两个集合的代表作为参数。 并查集森林 是一种将每一个集合以树表示的数据结构,其中 每一个节点保存着到它的父节点的引用 比如上面是两个集合分别记为A和B,集合A有4个元素,集合B有3个元素,每个元素都只对应一个集合,也就是一对一,对于集合的表示,通常都是使用根节点来判断,也就是说,1和5分别表示两个集合 //集合1的元素 1,2,3,4 //集合5的元素 5,6,7 那么 find(1)=1 find(2)=1 find(3)=1 find(4)=1 find(5)=5 find(6)=5 find(7)=5 2.并查集的基本操作 2.1并查集的存储结构 并查集通常用一个数组来表示, int father[N]; 其中father[i

并查集入门到再入门

余生长醉 提交于 2019-12-18 09:38:39
初进ACM的话,并查集考点不会太难。(鄙人愚见,若遇变态题,勿喷) 所以知道这个概念后,知识点没深入过,一直感觉是初学状态,最近又遇到这类基础题,便写此文,权当再入门一遍。 并查集概念(来自百度): 并查集是一种树型的数据结构,用于处理一些 不相交集合 (Disjoint Sets)的合并及查询问题。常常在使用中以森林来表示。集就是让每个元素构成一个单元素的集合,也就是按一定顺序将属于同一组的元素所在的集合合并。 说说我自己的理解: 初学阶段遇到的题型:几个离散点,给他们建关系,然后问些基础问题。比如 判断两个点是否有关系(连通)?(基础) 还有几个点是离散的?(经典例题:畅通工程) 判断其中是否构成回路?(经典例题:小希的迷宫) 找一个根,问这个根上面有多少结点?(基础) 乱七八糟的关系(中难题:食物链) (文章最后给例题链接) 并查集的复杂度:O(1) 比如说,我们要在一个无重复数据的数组中寻找一个指定的元素,那么最简单的方法就是直接for循环一遍暴力查找即可。暴力的时间复杂度为O(n)。 再比如,如何判断一个简单无向图是否为连通图(图一般会以二元组序列形式给出)dfs/bfs直接搜索(空间复杂度为O(n*n) (邻接矩阵存图)、O(n)(邻接表存图,但是vector会额外占用大量时间),时间复杂度为O(n),因为如果联通,每个点都会被搜索到有且仅有一遍) 当然有特殊情况,