并查集

并查集 知识点

人盡茶涼 提交于 2020-02-26 19:28:46
并查集学习: l 并查集: ( union-find sets) 一种简单的用途广泛的集合. 并查集是若干个不相交集合,能够实现较快的合并和判断元素所在集合的操作,应用很多,如其求无向图的连通分量个数等。最完美的应用当属:实现Kruskar算法求最小生成树。 l 并查集的精髓(即它的三种操作,结合实现代码模板进行理解): 1 、Make_Set(x) 把每一个元素初始化为一个集合 初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变)。 2 、Find_Set(x) 查找一个元素所在的集合 查找一个元素所在的集合,其精髓是找到这个元素所在集合的祖先!这个才是并查集判断和合并的最终依据。 判断两个元素是否属于同一集合,只要看他们所在集合的祖先是否相同即可。 合并两个集合,也是使一个集合的祖先成为另一个集合的祖先,具体见示意图 3 、Union(x,y) 合并x,y所在的两个集合 合并两个不相交集合操作很简单: 利用Find_Set找到其中两个集合的祖先,将一个集合的祖先指向另一个集合的祖先。如图 l 并查集的优化 1 、Find_Set(x)时 路径压缩 寻找祖先时我们一般采用递归查找,但是当元素很多亦或是整棵树变为一条链时,每次Find_Set(x)都是O(n)的复杂度,有没有办法减小这个复杂度呢? 答案是肯定的,这就是路径压缩,即当我们经过

并查集

烂漫一生 提交于 2020-02-26 19:27:23
并查集: ( union-find sets) 一种简单的用途广泛的集合. 并查集是若干个不相交集合,能够实现较快的合并和判断元素所在集合的操作,应用很多,如其求无向图的连通分量个数等。最完美的应用当属:实现Kruskar算法求最小生成树。 l 并查集的精髓(即它的三种操作,结合实现代码模板进行理解): 1 、Make_Set(x) 把每一个元素初始化为一个集合 初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变)。 2 、Find_Set(x) 查找一个元素所在的集合 查找一个元素所在的集合,其精髓是找到这个元素所在集合的祖先!这个才是并查集判断和合并的最终依据。 判断两个元素是否属于同一集合,只要看他们所在集合的祖先是否相同即可。 合并两个集合,也是使一个集合的祖先成为另一个集合的祖先,具体见示意图 3 、Union(x,y) 合并x,y所在的两个集合 合并两个不相交集合操作很简单: 利用Find_Set找到其中两个集合的祖先,将一个集合的祖先指向另一个集合的祖先。如图 l 并查集的优化 1 、Find_Set(x)时 路径压缩 寻找祖先时我们一般采用递归查找,但是当元素很多亦或是整棵树变为一条链时,每次Find_Set(x)都是O(n)的复杂度,有没有办法减小这个复杂度呢? 答案是肯定的,这就是路径压缩,即当我们经过"递推"找到祖先节点后

练习一D

喜你入骨 提交于 2020-02-26 15:11:49
这题感觉算半个思路题主要要想到有几对纠缠在一起假设有n对纠缠在一起那就有n-1不才能复原,然后用并查集把纠缠在一起的算一个集合,并查集,算一下就出来了 #include<bits/stdc++.h> using namespace std; int f[100005],sum[100005]; int find(int x){ while(x!=f[x]){ x=f[x]; } return x; } int main(){ int n,x,y; while(~scanf("%d",&n)){ for(int i=0;i<n;i++){ f[i]=i; sum[i]=1; } for(int i=0;i<n;i++){ int x,y; scanf("%d%d",&x,&y); x=find(x/2); y=find(y/2); if(x!=y){ f[x]=y; sum[y]+=sum[x]; } } int ans=0; for(int i=0;i<n;i++){ if(f[i]==i){ ans+=sum[i]-1; } } printf("%d\n",ans); } } 来源: CSDN 作者: 赵志锋 链接: https://blog.csdn.net/weixin_43981945/article/details/104515863

关押罪犯(种类并查集)

放肆的年华 提交于 2020-02-24 06:32:09
关押罪犯 //洛谷P1525关押罪犯 # include <bits/stdc++.h> using namespace std ; const int N = 1e5 + 10 ; int p [ N << 1 ] ; struct M { int a , b , c ; bool operator < ( const M & T ) const { return c > T . c ; } } ; int find ( int x ) { if ( p [ x ] != x ) p [ x ] = find ( p [ x ] ) ; return p [ x ] ; } int main ( ) { int n , m ; cin >> n >> m ; for ( int i = 1 ; i <= n ; i ++ ) p [ i ] = i ; M d [ m ] ; for ( int i = 0 ; i < m ; i ++ ) { scanf ( "%d%d%d" , & d [ i ] . a , & d [ i ] . b , & d [ i ] . c ) ; } sort ( d , d + m ) ; for ( int i = 1 ; i <= 2 * n ; i ++ ) p [ i ] = i ; for ( int i = 0 ; i < m ;

PAT Advanced 1034 Head of a Gang (30) [图的遍历,BFS,DFS,并查集]

ぐ巨炮叔叔 提交于 2020-02-23 11:24:59
题目 One way that the police finds the head of a gang is to check people’s phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls made between the two persons. A “Gang” is a cluster of more than 2 persons who are related to each other with total relation weight being greater than a given threshold K. In each gang, the one with maximum total weight is the head. Now given a list of phone calls, you are supposed to find the gangs and the heads. Input Specification: Each input file

并查集--How Many Tables

廉价感情. 提交于 2020-02-23 03:34:14
并查集–How Many Tables Description 今天是伊格纳修斯的生日。他邀请了很多朋友。现在是吃晚饭的时间了。伊格纳修斯想知道他至少需要多少张桌子。你必须注意到,并不是所有的朋友都相互认识,而且所有的朋友都不想和陌生人呆在一起。 这个问题的一个重要规则是,如果我告诉你A认识B,B认识C,那就意味着A,B,C彼此认识,所以他们可以呆在一张桌子上。 例如:如果我告诉你A知道B,B知道C,D知道E,那么A,B,C可以住在一张桌子上,而D,E必须住在另一张桌子上。所以伊格纳修斯至少需要两张桌子。 Input 输入以整数T(1<=T<=25)开始,表示测试用例的数量。然后是T测试用例。每个测试用例以两个整数N和M(1<=N,M<=1000)开始。N表示好友的数量,好友标记为从1到N,然后是M行。每行由两个整数A和B(A!=B)组成,这意味着朋友A和朋友B彼此认识。两个箱子之间将有一条空行。 Output 对于每个测试用例,只需输出Ignatius至少需要多少个桌子。请勿打印任何空白。 Sample Input 2 5 3 1 2 2 3 4 5 5 1 2 5 Sample Output 2 4 先合并集合,在遍历共有几个不同的集合 # include <iostream> # include <cstdio> # include <algorithm> # include

并查集的python实现

依然范特西╮ 提交于 2020-02-22 15:50:08
import numpy as np import os class DIS_JOIN(object): def __init__(self): ''' 并查集算法 拥有两个函数 一个是把某个元素放在某个集合中 另一个是返回一个list,包含所有集合和集合中所有的点 ''' self.Set = None self.Sum = None self.n = None def clear(self, n): ''' 初始化 n为一共有多少个元素 ''' self.Set = np.zeros(n, dtype=int) self.Set = self.Set - 1 # 都初始化为-1. 表示他自己就是根. Set是一个数组. # Set[i] 表示i的根是谁. self.Sum = n self.n = n return def find_r(self, p): ''' 返回p属于那一个集合 ''' if self.Set[p] < 0: return p self.Set[p] = self.find_r(self.Set[p]) #通过迭代不停的找根. return self.Set[p] def join(self, a, b): ''' 将元素b加入元素a所在的集合中 ''' ra = self.find_r(a) rb = self.find_r(b) if (ra !=

PAT刷题日志 2020/2/20

牧云@^-^@ 提交于 2020-02-22 04:31:22
开始图的部分: 第一题:1013 Battle Over Cities (25分) 这个题目大意就是给出一个无向图,现在每次删除其中的一个点,然后问剩余部分需要添加几条边才能连接起来,相当于计算剩余部分的连通区域个数,其实可以用dfs进行遍历,遇到删除点就return停止,然后访问过的点设置为true,然后连通区域个数+1,这样遍历完一遍图就可以统计出来互相独立的连通区域个数。 不过对于这个题我第一想到的是刚学过的并查集,不过由于我是并查集新手,尝试实现的时候并没有达到效果,还好参考了算法笔记豁然开朗。 并查集需要对不同的删除点创建不同的并查集合,然后统计根节点的个数,相对还是比较有意思的。 第二题:1021 Deepest Root (25分) 这个我完全按自己的想法,用了并查集合dfs写出来,提交直接AC,感觉很爽,不过跑出来了900ms,哈哈 这个题其实也可以不用并查集,也可以用一个flag数组配合dfs进行遍历所有节点,这样也可以判断连通分量。 第三题:1034 Head of a Gang (30分) 这个比较复杂,不仅统计连通分量,还要计算每个的权值以及总的权值, ohh,我写了至少两个小时,改了bfs和dfs,最终竟然都得了20分,而且错的地方都是一样的。。。。。好吧,超出能力。。 来源: CSDN 作者: 如椽大笔_S686 链接: https://blog

贪心 & 并查集压缩路径 -- Supermarket POJ - 1456

寵の児 提交于 2020-02-21 11:36:24
Supermarket POJ - 1456 题意: 是买卖N件东西,每件东西都有个截止时间,在截止时间之前买都可以,而每个单位时间只能买一件。问最大获利。 思路: 用贪心做,用并查集来加快速度,太精妙了。 如果购买不冲突,那么全部买下来就可以了。存在冲突,就需要取舍。显然在冲突的时候我们选择价格高的更优,如此就可以用贪心的算法。先将物品按照价格从高到底的顺序排列,购买一个就在时间点上做一个标记,只要不冲突就可以购买。 如何快速找到第一个不冲突的时间点呢,使用并查集很好得解决了这个问题。 这里并查集的作用类似于链表指针,压缩的过程就是删掉节点的过程。从而在O(1)的时间内找到那个不冲突的点。 code: # include <stdio.h> # include <string.h> # include <iostream> # include <algorithm> using namespace std ; const int maxn = 10010 ; int F [ maxn ] ; truct Node { int p , d ; } node [ MAXN ] ; bool cmp ( Node a , Node b ) { return a . p > b . p ; } int find ( int x ) { if ( F [ x ] == - 1 )

【算法提高班】并查集

若如初见. 提交于 2020-02-21 03:08:45
关于并查集的题目不少,官方给的数据是 30 道(截止 2020-02-20),但是有一些题目虽然官方没有贴 并查集 标签,但是使用并查集来说确非常简单。这类题目如果掌握模板,那么刷这种题会非常快,并且犯错的概率会大大降低,这就是模板的好处。 我这里总结了几道并查集的题目: 547.朋友圈 721. 账户合并 990. 等式方程的可满足性 大家可以学了模板之后去套用一下上面的三道题,做不出来的可以看看我的题解。 并查集概述 并查集算法,主要是解决图论中「动态连通性」问题的 Union-Find 算法解决的是图的动态连通性问题,这个算法本身不难,能不能应用出来主要是看你抽象问题的能力,是否能够把原始问题抽象成一个有关图论的问题。 如果你对这个算法不是很明白,推荐看一下这篇文章 Union-Find 算法详解 ,讲的非常详细。 你可以把并查集的元素看成部门的人,几个人可以组成一个部门个数。 并查集核心的三个方法分别是 union , find , connected 。 union : 将两个人所在的两个部门合并成一个部门(如果两个人是相同部门,实际山不需要合并) (图来自 labuladong) find : 查找某个人的部门 leader connnected : 判断两个人是否是一个部门的 (图来自 labuladong) 模板 这是一个我经常使用的模板