并查集

并查集-The Suspects POJ - 1611

偶尔善良 提交于 2020-01-20 21:52:22
并查集-The Suspects POJ - 1611 题目: 2003年4月16日,世界卫生组织根据包括中国内地和香港地区,加拿大、美国在内的11个国家和地区的13个实验室通力合作研究的结果,宣布重症急性呼吸综合征的病因是一种新型的冠状病毒,称为SARS冠状病毒。 很不幸,小明同学昨天晚上被确诊以经感染非典病毒,为此,校医院需要对他隔离治疗并隔离观察与他直接或间接接触者。 可以认为,同一个社团内如果有人感染病毒或可能感染病毒,那么这个社团内所有人都被认为是可能已经感染了病毒,由于时间紧迫,需要尽快找到所有可能携带病毒的同学并隔离,以防止更大范围的病毒扩散,院长请你帮忙编写程序计算需要隔离多少人 Input 输入文件包含多组数据。 对于每组测试数据: 第一行为两个整数n和m 其中n是学生的数量,m是学生社团的数量。0 < n <= 30000 , 0 <= m <= 500 每个学生编号是一个0到n-1之间的整数,已知小明同学编号是0 紧随其后的是团体的成员列表,每组一行。 每一行有一个整数k,代表成员数量。之后有k个整数代表这个群体的学生。一行中的所有整数由至少一个空格隔开。 n = m = 0表示输入结束,不需要处理。 Output 对于每组测试数据 输出需要隔离的人数,每组输出占一行 Sample Input 100 4 2 1 2 5 10 13 11 12 14 2 0

并查集学习笔记

ⅰ亾dé卋堺 提交于 2020-01-20 08:21:49
前言: “十年苦琢白玉璧 一朝竞放紫兰花” 有的东西只要你肯用心学,总能学的很好。 我觉得上面这句话很适合我,毕竟就是凭着这不怕苦的精神,我才从一个连路径压缩都打不对的并查集小白成长成了普通并查集OIER( 毕竟我也不是大佬 ) 并查集是什么? 并查集是一种用某个代表来代表整个集合,进而再进行对集合的操作的数据结构 比如我们用3来代表{1,2,3,4,5}这个集合,我们就表示成: p[1]=3 p[2]=3 p[3]=3 p[4]=3 p[5]=3 这里的p[a]=b就表示 a属于b 长什么样? 为什么要问这个问题呢,因为这可能会对等会理解路径压缩有帮助 我们来看集合里的包含关系: A⊊B C⊊B A={1,2,3},C={4,5},则B={1,2,3,4,5} 我们把4拿出来当做集合B的代表,这个图就是这样子的: 棕色代表集合A,绿色代表集合C,整个就代表B 这里集合A我没选代表… 类似的,再给出一个例子: 可能我的画技有点问题… 怎么写? 上文说p[x]表示的就是x所属于的集合 因此我们 预处理 需要这样: void iint(){ for(int i=1;i<=n;i++) p[i]=i;//每一个元素一开始所属集合代表就是自己 } 那么我们的 找集合 代码就是这样写了: int Find(int x){ if(p[x]==x) return x; else return

并查集

拜拜、爱过 提交于 2020-01-19 23:31:31
void init() { for(int i = 1; i <= N; i++) f[i] = i; } int find(int k) { return f[k] == k? k : f[k] = find(f[k]); } int union(int a, int b) { f[find(b)] = find(a); } 带权并查集 假定a、b是两个结点且a > b,a -> b表示区间[b, a)的和,b -> a表示负的区间[b, a)的和。 需要将结点对转化为一种左开右闭的形式以方便连接。 假设W1是要添加的边,W4是实际添加的边,它们之间的关系如下图所示。 对于路径压缩,直接累加各边权即可。 例题:HDU3038 http://acm.hdu.edu.cn/showproblem.php?pid=3038 //样例输入 10 5 1 10 100 7 10 28 1 3 32 4 6 41 6 6 1 //样例输出 1 将这个求解过程可视化。 #include<bits/stdc++.h> using namespace std; int f[200010], w[200010]; int find(int k) { if(k != f[k]) { int a = find(f[k]); w[k] += w[f[k]]; f[k] = a; } return f[k]

并查集结构+岛问题+前缀树+贪心策略

坚强是说给别人听的谎言 提交于 2020-01-19 20:12:05
左神算法初级班第七节 并查集结构 岛问题 何为前缀树?如何生成前缀树? 贪心策略 (from左神算法初级班第七节) 1.并查集结构 优点(两个功能非常快): 1)查询两个元素是否是一个集合 2)两个各自所在的集合合并成一个集合 list和set无法在很低的时间复杂度下完成。 1)查询两个元素是否是一个结合? 每个结合的第一个节点有一个指针指会自己(代表节点) 每个节点指向父节点 查询两个元素是否是一个集合,向上找到两个元素的代表节点(头结点),如果两个代表节点是同一节点,则两个元素在同一个集合中。 2)两个各自所在的集合合并成一个集合 那个集合少就挂到多的集合的底下。 3)优化: 查询操作后,将查询路径打平(如图)。 4)代码: public static class UnionFindSet { public HashMap < Node , Node > fatherMap ; //key:child,value:父节点。查找节点的父节点 public HashMap < Node , Integer > sizeMap ; //某一个节点所在的集合有多少节点 public UnionFindSet ( List < Node > nodes ) { makeSet ( nodes ) ; } public void makeSets ( List < Node > nodes

并查集

落爺英雄遲暮 提交于 2020-01-18 21:05:16
介绍 #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #define N 1000010 using namespace std; int fa[N]; int find(int x) { if(fa[x]==x) return x; int t=find(fa[x]); fa[x]=t; return t; //return fa[x]==x?x:fa[x]=find(fa[x]); } void merge(int x,int y) { x=find(x); y=find(y); if(x==y) return; fa[x]=y; } int m,x[N],y[N],f[N]; void doit() { memset(fa,0,sizeof(fa)); for(int i=1;i<=1000000;i++) fa[i]=i; cin>>m; for(int i=1;i<=m;i++) { cin>>x[i]>>y[i]>>f[i]; if(f[i]==1) merge(x[i],y[i]); } bool ans=true; for(int i=1;i<=m;i++) { if(f[i]==0) { if(find(x[i])==find(y[i])) ans=false; }

并查集:反集

懵懂的女人 提交于 2020-01-18 17:35:01
我朋友的朋友是我的朋友; 我敌人的敌人也是我的朋友。 一般这种情况我们会采用反集的思想: 如果a和b是敌人,合并n+b和a,n+a和b 如果c和a是敌人,合并n+c和a,n+a和c 那么b和c就通过a+n合并在一起了。 来源: https://www.cnblogs.com/kgmfgm35/p/12209494.html

【Nov 10,哈希与并查集】模拟赛题解

陌路散爱 提交于 2020-01-18 02:40:35
学习炜哥,最后再发代码。 No.1 distinct 【问题描述】 陶陶为了给一道平面几何题出数据,需要产生 N 个点(x[i],y[i])。已知 x,y 是由伪随机函数顺序产生,即: X[i+1] = (X[i]*Ax+Bx+i) mod Cx (X[1], Ax,Bx,Cx 是事先给定的) Y[i+1] = (Y[i]*Ay+By+i) mod Cy (Y[1], Ay,By,Cy 是事先给定的) 这样,就可以快速连续产生很多点坐标(X[i], Y[i])。 不幸的是,这样产生的点有可能有相同的,虽然这种几率很少,但严谨的陶陶不允许这种事发生。陶陶要求你帮助他解决最少要产生前多少项时,正好有 N 个不相同的点。 【输入格式】第一行。一个整数 N . 第二行:4 个整数 X[1]、 Ax、Bx、Cx . 第三行:4 个整数 Y[1]、 Ay、By、Cy . 【输出格式】 一个整数 M 。表示最少要连续产生 M 个点,正好有 N 个不相同的点。数据保证有答案。 【数据范围】1<=N<=1,000,000, 其它所有数据都在[1...1,000,000,000]范围内。 【输入样例】21 2 4 3 6 5 2 3 13 【输出样例】 24 很单纯的Hash。将求出的x与y分别成一个大质数,加起来模一个大质数即可。 No.2 Allbarns 【题目描述】

【洛谷 3367】模板并查集

喜夏-厌秋 提交于 2020-01-18 01:17:57
题目描述 如题,现在有一个并查集,你需要完成合并和查询操作。 输入输出格式 输入格式: 第一行包含两个整数N、M,表示共有N个元素和M个操作。 接下来M行,每行包含三个整数Zi、Xi、Yi 当Zi=1时,将Xi与Yi所在的集合合并 当Zi=2时,输出Xi与Yi是否在同一集合内,是的话输出Y;否则话输出N 输出格式: 如上,对于每一个Zi=2的操作,都有一行输出,每行包含一个大写字母,为Y或者N 输入输出样例 输入样例#1: 复制 4 7 2 1 2 1 1 2 2 1 2 1 3 4 2 1 4 1 2 3 2 1 4 输出样例#1: 复制 N Y N Y 说明 时空限制:1000ms,128M 数据规模: 对于30%的数据,N<=10,M<=20; 对于70%的数据,N<=100,M<=1000; 对于100%的数据,N<=10000,M<=200000。 题解:不需要题解咳咳咳,和亲戚那道题好像啊。 //#include<bits/stdc++.h> #include<iostream> #include<algorithm> #include<queue> #include<cmath> #include<cstring> #include<cstdlib> #include<cstdio> using namespace std; int n,m,p,a,b,s1,s2

洛谷P2024 食物链 【并查集】

痴心易碎 提交于 2020-01-17 01:43:31
题目描述 动物王国中有三类动物 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 句话有的是真的,有的是假的。当一句话满足下列三条之一时,这句话就是假话,否则就是真话。 • 当前的话与前面的某些真的话冲突,就是假话 • 当前的话中 X 或 Y 比 N 大,就是假话 • 当前的话表示 X 吃 X,就是假话 你的任务是根据给定的 N 和 K 句话,输出假话的总数。 标题输入格式 第一行两个整数,N,K,表示有 N 个动物,K 句话。 第二行开始每行一句话(按照题目要求,见样例) 输出格式 一行,一个整数,表示假话的总数。 这题是我在学习 查并集 的时候遇到的,所以想当然的用并查集来做了。 并查集内的每一个组表示组内所有元素发生或不发生 # include <iostream> # include <algorithm> # include <string> # include <sstream> # include

字典树 + 并查集 + 滑动窗口 + 优先队列 demo

拜拜、爱过 提交于 2020-01-16 09:57:25
统计一段时间内(500)单词出现的频率 单词最长为10 void init(); 初始化函数 void searchWord(int tsec, char str[], int num); 在tsec时刻,搜索了某一个单词str, 它的频率是num void banWord(int tsec, char str[]); 在tsec时刻,ban到了单词str,在以后的rank中不会再出现str void mergeWords(int tsec, char str1[], char str2[]); 在tsec时刻,合并单词,str2不在出现在rank中,且str2的频率都计算到str1中,相当于父子关系 int getRank10(int, char[][MAX_WORD_LEN + 1]); 在tsec时刻,返回该时刻以及前500s内的所有单词出现频率最高的单词。 # define MAX_WORD_LEN 10 # define USEFUL 0 # define BAN 1 # define MERGED 2 static void mstrcpy ( char dest [ ] , const char src [ ] ) { int i = 0 ; while ( ( dest [ i ] = src [ i ] ) != '\0' ) i ++ ; } static