模板:并查集
(好的期末考试考砸的我滚回来写代码来了TAT)
(咦我什么时候期末考试考好过~~)
却说勇者有很多的亲戚,亲戚又有很多的亲戚,亲戚的亲戚就是自己的亲戚。
不幸的是,亲戚中有些人不是很有钱,所以说会管勇者借钱。
勇者丝毫不介意啊,毕竟自从他讨伐完大龙之后,他就日日有国王一个金币的俸禄。
可是,终有一天,勇者发现一天之内,亲戚就来了十多个。
还是路由器发现的,他将族谱整理完之后才告诉他说:“那些人有一半都不是你们家族的,就是过来诈骗的!”
勇者哑口无言,为了拯救自己的金币,他需要知道哪些人是自己的亲戚。
——————————————
输入格式:
第一行包含两个整数N、M,表示共有N个人和M次操作。
接下来M行,每行包含三个整数Zi、Xi、Yi
当Zi=1时,表示Xi与Yi是亲戚
当Zi=2时,输出Xi与Yi是否是亲戚,是的话输出Y;否则话输出N
输出格式:
如上,对于每一个Zi=2的操作,都有一行输出,每行包含一个大写字母,为Y或者N
提示:
亲戚的亲戚是亲戚
——————————————
(题外话)
好的,我们接下来就是要讲一个高深莫测玄幻之际的——并查集。
好吧在路由器没学之前一直以为并查集是huge佬所学的。
那么今天将带给蒟蒻也能看懂的并查集教程!
首先让我们知道并查集的作用:简短点说,就是需要完成的任务有1.合并集合2.查询两个元素是否在同一个集合内。
上面那句话一定要看懂再往下看(不然你会和路由器一样当机半小时)
那么,让我们正式开始。
——————————————
勇者花费了一天的时间,终于找齐了所有七大姑八大姨了,那么接下来就是需要靠古老魔法的帮助来完成族谱了。
路由器也在照相馆中找到了魔法书,上面赫然写着三个字。
并查集。
“并查集的实现是类似于树一般,一整棵树代表了一整个集合。这样做的好处是,我们要想知道元素是否在同一个集合内,只需要看他们所在的集合的根节点是否一样即可。”
“但是,这并非意味着图论,因为链式前向星有很大的空间限制。”
“我们用一个很简单的方法实现建树——fa数组(指father,不要想象成奇怪的东西)”
“fa数组的作用,fa[i]=j表示j是i的爸爸。规定根节点的爸爸为根节点。”
“这样,当我们知道了要合并的两个元素i,j时,找到i与j的根节点if,jf,我们就可以简单粗暴的用fa[if]= jf来实现。”
“那么就只有一个问题了,查询。”
“查询方法:即不断递归,就是fa套fa套fa套fa……直到fa[i]=i,这时候我们就找到了所在集合的根节点了。”
“然后比较这样得到的根节点即可,相等,即为一个集合……”
勇者“啪”的一声跑了出去,然后用自己的魔法代码功力敲完了魔法。
(但是这个魔法有缺陷,因此不贴出啦!实际上是懒~)
然而有一天,勇者气喘吁吁的找到了路由器。
“路由器,那个魔法……他,不管用了!”
“啊?怎么回事?”路由器疑惑问道。
“额……我把这个魔法卖给了精灵族,但他们第二天就要求退货,说不灵了。”
“不灵到不至于,怕不是太慢。”路由器懒洋洋地说,“那到底怎么回事啊?”
“因为精灵能活千多岁……所以,”勇者支吾道,“他们将自己输入,再把爸爸输入,再爷爷,再太爷爷,再太太爷爷,再太太太爷爷,再……”
“行了,我知道什么问题了,”路由器拜拜手,“你还是把书好好看看吧!”
勇者拿起书,将最后一点问题看完。
“……然而,有的时候,这样做出来的树实际上只有几个支链,有的甚至没有支链,那么找的速度就会明显增加。”
“但是解决的办法也很简单——我们先查一遍,然后把所有沿途遇到的元素的爸爸(fa)全设为根节点即可。”
“以下是本书附带魔法代码,如有不懂参看注释。”
#include<cstdio> #include<cstring> #include<iostream> #include<cmath> #include<algorithm> using namespace std; int fa[10001]={0}; int find(int a){//找到a所在的集合的根节点 if(fa[a]!=a)fa[a]=find(fa[a]); //路径压缩优化 //当我们找到根节点的时候 //我们将这一路上我们往上爬的所有的节点 //全部指向这个根节点,这样再搜就会很快 return fa[a]; //最开始的时候,我们碰到了第一个fa[a]==a //此时我们就知道了fa[a]为根节点 //将fa[a]的值传递给上一个fa[a],完成路径压缩 //经过压缩之后到这个a,此时fa[a]就是根节点 } void judge(int a,int b){//判断是否在同一个集合里 if(find(a)!=find(b)){ printf("N\n"); }else{ printf("Y\n"); } return; } void unionn(int a,int b){//合并以a,b为*根节点*与的两个集合 fa[b]=a;//简单粗暴的将两棵树连接起来 return; } int main(){ int n,m;//N个元素和M个操作 scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ fa[i]=i; //初始化,将每一个集合视为一棵树 //则开始时对于每一个元素,他的根节点就是他本身 } for(int i=1;i<=m;i++){ int a1,b1,a,b,z; scanf("%d%d%d",&z,&a,&b); if(z==1){ a1=find(a); b1=find(b); if(a1!=b1){//不是同一个集合 unionn(a1,b1); } }else{ judge(a,b); } } return 0; }
下面附带模板题:
洛谷 P3367 【模板】并查集:https://www.luogu.org/problem/show?pid=3367#sub
真的是模板,你只需要将上面的程序复制粘贴就AC啦!
- 并查集模板
- 杭电-1232 畅通工程(并查集模板)
- 并查集模板
- 并查集简介及模板
- HDU 1856 More is better (并查集模板题)
- POJ-1213 How Many Tables (并查集模板题)
- HDU 1213 How Many Tables(模板——并查集)
- POJ 2524 宗教信仰 并查集 基础模板
- 并查集的两个模板
- 并查集模板题-HDU1856
- hdu1231 并查集模板题
- 并查集讲解(按秩合并与路径压缩),模板与典型例题
- 并查集 模板
- Find them, Catch them POJ - 1703(并查集,模板)
- hdu 1213 求连通分量(并查集模板题)
- poj 2524 求连通分量(并查集模板题)
- 模板:并查集
- 并查集模板
- gw_Disjoint Set (并查集) 模板及拓展应用
- PAT甲题题解-1114. Family Property (25)-(并查集模板题)