并查集

并查集实现kruskal算法

两盒软妹~` 提交于 2020-03-02 18:51:19
kruskal算法:求最小生成树,给定n个节点,m条边和边的权值,创建一个总权值最小的树 这里用到了并查集的思想:如果要加入的边两个顶点在同一个集合里(代码里即为find(int x)相同),就说明会形成环,这是不行的,否则抓出最小的那条边,放入集合之中,并且标记这条边,下次遍历的时候跳过 到集合总边数为n-1时,不必再寻找,跳出循环。 # include <iostream> # include <algorithm> # define maxn 100 using namespace std ; int fa [ maxn ] ; int edge [ maxn ] [ maxn ] ; int vis [ maxn ] ; typedef struct node { int to ; int end ; int x ; //权值 } node ; node nod [ maxn ] ; void init ( int n ) { for ( int i = 1 ; i <= n ; i ++ ) { fa [ i ] = i ; } } int find ( int x ) { if ( x == fa [ x ] ) return x ; else return fa [ x ] = find ( fa [ x ] ) ; } void uni ( int x , int

NOI2001 食物链 带权并查集

♀尐吖头ヾ 提交于 2020-03-02 01:16:11
一、内容 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形。 A吃B, B吃C,C吃A。 现有N个动物,以1-N编号。 每个动物都是A,B,C中的一种,但是我们并不知道它到底是哪一种。 有人用两种说法对这N个动物所构成的食物链关系进行描述: 第一种说法是”1 X Y”,表示X和Y是同类。 第二种说法是”2 X Y”,表示X吃Y。 此人对N个动物,用上述两种说法,一句接一句地说出K句话,这K句话有的是真的,有的是假的。 当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 1) 当前的话与前面的某些真的话冲突,就是假话; 2) 当前的话中X或Y比N大,就是假话; 3) 当前的话表示X吃X,就是假话。 你的任务是根据给定的N和K句话,输出假话的总数。 输入格式 第一行是两个整数N和K,以一个空格分隔。 以下K行每行是三个正整数 D,X,Y,两数之间用一个空格隔开,其中D表示说法的种类。 若D=1,则表示X和Y是同类。 若D=2,则表示X吃Y。 输出格式 只有一个整数,表示假话的数目。 数据范围 1≤N≤50000,0≤K≤100000 输入样例: 100 7 1 101 1 2 1 2 2 2 3 2 3 3 1 1 3 2 3 1 1 5 5 输出样例: 3 二、思路 - 判断x吃y同理。 三、代码 # include <cstdio> # include

[kuangbin带你飞]专题五 并查集 B - The Suspects

眉间皱痕 提交于 2020-03-01 18:43:08
B - The Suspects 题目链接: https://vjudge.net/contest/66964#problem/B 题目: Severe acute respiratory syndrome (SARS), an atypical pneumonia of unknown aetiology, was recognized as a global threat in mid-March 2003. To minimize transmission to others, the best strategy is to separate the suspects from others. In the Not-Spreading-Your-Sickness University (NSYSU), there are many student groups. Students in the same group intercommunicate with each other frequently, and a student may join several groups. To prevent the possible transmissions of SARS, the NSYSU collects the member lists of all student

并查集

落花浮王杯 提交于 2020-03-01 18:36:58
1. 引出并查集 并查集,英文译为Disjoint Set,即不相交集合。常用来解决集合相交问题。为什么叫并查集呢?这是因为并查集中包括两个主要的步骤:(1)合 并 (2)查 找 。不妨看看下面的例题: 在某个城市里住着n个人,任何两个认识的人不是朋友就是敌人,而且满足: n 我朋友的朋友是我的朋友; n 我敌人的敌人是我的朋友; 已知关于 n个人的m条信息(即某2个人是朋友或者敌人),假设所有是朋友的人一定属于同一个团伙,请计算该城市最多有多少团伙? 分析: 要知道有多少个团伙,就要知道每个人属于哪个团伙?还有做到的是若A属于Team1同时也属于Team2那么就要合并Team1和Team2。这就是并查集的“并”和“查”了。显然天生就要用到并查集解决这个题了。 2. 并查集实现 2.1 现在来看看怎么实现并查集算法吧?主要看看并(merge)和查(find)怎么实现? 还是举个例子吧。存在下面的几个集合 {1,3,7}, {4}, {2,5,9,10}, {6,8} , 如果用编号最小的元素标记所在集合即为 set[i] 。表示如下: i 1 2 3 4 5 6 7 8 9 10 set[i] 1 2 1 4 2 6 1 6 2 2 对应的代码: find1(x) { return set[x]; } Merge1(a,b) { i = min(a,b); j = max(a,b)

[转]图论题集

假如想象 提交于 2020-02-29 20:23:55
========以下是最小生成树+并查集========== HDU 1213 基础并查集★ HDU 1272 基础并查集★ HDU 1325 Tree? HDU 1856 基础并查集★ HDU 1102 基础最小生成树★ HDU 1232 基础并查集★ HDU 1233 基础最小生成树★ HDU 1863 基础最小生成树★ HDU 1875 基础最小生成树★ HDU 1879 基础最小生成树★ HDU 3371 简单最小生成树★ HDU 1301 基础最小生成树★ HDU 1162 基础最小生成树★ HDU 1198 基础最小生成树★ HDU 1598 HDU 1811 并查集+拓扑排序★★ HDU 3926 同构图★ HDU 3938 离线+并查集★★ HDU 2489 dfs枚举组合情况+最小生成树★ HDU 4081 National HDU 4126 Conqueror HDU 1829 基础种类并查集★ HDU 1558 计算几何+并查集★ HDU 3461 并查集(有点难想到)★★ HDU 3367 最大生成树★ HDU 2473 并查集+设立虚父节点(马甲)★★ HDU 3172 带权并查集★ HDU 3635 带权并查集★ HDU 3047 带权并查集★ HDU 3038 HDU 2818 带权并查集★ HDU 3234 异或并查集(难)★★★ HDU 2121

P1551 亲戚(并查集)

假如想象 提交于 2020-02-29 15:45:45
亲戚 题目背景 若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。 题目描述 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。 输入格式 第一行:三个整数n,m,p,(n<=5000,m<=5000,p<=5000),分别表示有n个人,m个亲戚关系,询问p对亲戚关系。 以下m行:每行两个数Mi,Mj,1<=Mi,Mj<=N,表示Mi和Mj具有亲戚关系。 接下来p行:每行两个数Pi,Pj,询问Pi和Pj是否具有亲戚关系。 输出格式 P行,每行一个’Yes’或’No’。表示第i个询问的答案为“具有”或“不具有”亲戚关系。 输入输出样例 输入 6 5 3 1 2 1 5 3 4 5 2 1 3 1 4 2 3 5 6 输出 Yes Yes No 说明/提示 非常简单的并查集入门题哦!!! 正解 就是一道 并查集模板 先用并查集合并 2到m+1行 ,每行的两个数字 再用find(),找,看 m+2到最后一行 的两个数是否在同一个集合 并查集 AC代码 # include <iostream> # include <cstdio> using namespace std ; int n , m , p , x , y , pre [ 5005 ]

P1455 搭配购买(并查集+dp)

[亡魂溺海] 提交于 2020-02-28 23:03:39
搭配购买 题目穿越门 题目描述 明天就是母亲节了,电脑组的小朋友们在忙碌的课业之余挖空心思想着该送什么礼物来表达自己的心意呢?听说在某个网站上有卖云朵的,小朋友们决定一同前往去看看这种神奇的商品,这个店里有n朵云,云朵已经被老板编号为1,2,3,……,n,并且每朵云都有一个价值,但是商店的老板是个很奇怪的人,他会告诉你一些云朵要搭配起来买才卖,也就是说买一朵云则与这朵云有搭配的云都要买,电脑组的你觉得这礼物实在是太新奇了,但是你的钱是有限的,所以你肯定是想用现有的钱买到尽量多价值的云。 输入格式 第1行n,m,w,表示n朵云,m个搭配和你现有的钱的数目 第2行至n+1行,每行ci,di表示i朵云的价钱和价值 第n+2至n+1+m ,每行ui,vi表示买ui就必须买vi,同理,如果买vi就必须买ui 输出格式 一行,表示可以获得的最大价值 输入输出样例 输入 5 3 10 3 10 3 10 3 10 5 100 10 1 1 3 3 2 4 2 输出 1 说明/提示 30%的数据满足:n<=100 50%的数据满足:n<=1000;m<=100;w<=1000; 100%的数据满足:n<=10000;0<=m<=5000;w<=10000. 正解 这道题正解就是并查集+01背包 下面是思路: 答案很明显是可以的。可以利用并查集,将这m组配对购买的商品划到一个集合里

并查集 HDU 1232

跟風遠走 提交于 2020-02-28 16:45:14
#include < iostream > #include < stdio.h > #include < string .h > using namespace std; bool flags[ 1001 ]; int father[ 1001 ]; void makeset( int n) { for ( int i = 1 ;i <= n;i ++ ) { father[i] = i; } } int findset( int x) { if (x != father[x]) { father[x] = findset(father[x]); } return father[x]; } void Union( int a, int b) { int x = findset(a); int y = findset(b); if (x == y) return ; father[y] = x; } int main() { int n,m; while (scanf( " %d %d " , & n, & m) != EOF) { memset(flags, false , sizeof (flags)); if (n == 0 ) break ; makeset(n); int first,second; for ( int i = 1 ;i <= m;i ++ ) {

并查集的使用

£可爱£侵袭症+ 提交于 2020-02-26 19:29:49
最近做项目的过程中用到了并查集的小知识,惭愧的是,我知道有这个数据结构,但是一时还想不起来她叫什么名字了,后来查找并自己实现了一下,发到这里来,以备后患! 不过,要讲一下并查集是怎么回事的话,需要用到一些图片啊什么,我去网上找了一下,发现 Cherish_yimi 写的很好,我就直接将它的说明拿过来了,更加详细的可以去看看她的博客,里面有它实现的代码,挺好的! 以下是他解释的部分,我就偷懒了 并查集学习: l 并查集: ( union-find sets) 一种简单的用途广泛的集合. 并查集是若干个不相交集合,能够实现较快的合并和判断元素所在集合的操作,应用很多,如其求无向图的连通分量个数等。最完美的应用当属:实现Kruskar算法求最小生成树。 l 并查集的精髓(即它的三种操作,结合实现代码模板进行理解): 1 、Make_Set(x) 把每一个元素初始化为一个集合 初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变)。 2 、Find_Set(x) 查找一个元素所在的集合 查找一个元素所在的集合,其精髓是找到这个元素所在集合的祖先!这个才是并查集判断和合并的最终依据。 判断两个元素是否属于同一集合,只要看他们所在集合的祖先是否相同即可。 合并两个集合,也是使一个集合的祖先成为另一个集合的祖先,具体见示意图 3 、Union(x,y) 合并x

并查集

耗尽温柔 提交于 2020-02-26 19:29:28
并查集 :(union-find sets) 是若干个不相交集合,能够实现较快的合并和判断元素所在集合的操作,应用很多,如其求无向图的连通分量个数等。最完美的应用当属:实现Kruskal算法求最小生成树。 并查集的精髓: 1、make_set(x) 把每一个元素初始化为一个集合 初始化后每一个元素的父亲节点是它本身,每一个元素的祖先节点也是它本身(也可以根据情况而变)。 2、find_set(x) 查找一个元素所在的集合(有两种方法:朴素查找和采用路径压缩的方法查找,其中路径压缩有递归和非递归) 查找一个元素所在的集合,其精髓是找到这个元素所在集合的祖先!这个才是并查集判断和合并的最终依据。判断两个元素是否属于同一集合,只要看他们所在集合的祖先是否相同即可。 3、Union(x,y) 合并x,y所在的两个集合: 利用Find_Set找到其中两个集合的祖先,将一个集合的祖先指向另一个集合的祖先。 并查集的优化 1、find_set(x)时 路径压缩 寻找祖先时我们一般采用递归查找,但是当元素很多亦或是整棵树变为一条链时,每次find_set(x)都是O(n)的复杂度,因此需要路径压缩,即当我们经过"递推"找到祖先节点后,"回溯"的时候顺便将它的子孙节点都直接指向祖先,这样以后再次find_set(x)时复杂度就变成O(1)了,路径压缩方便了以后的查找。 2、Union(x,y