赞
踩
目录
本文题目传送门:
并(unity)查(find)集(set),即可以合并、查找的树状数据结构,常用于处理不交集查询问题。
下面是一个典型例子:
图1中每个箭头两端连接的是两名呈同班同学关系的学生,请问,1号同学和5号同学是同一个班的吗?
我们简化一下,就是如果我们能确定任意两个人之间是不是同班同学,我们能不能确定所有同学之间是不是同班同学。
在简化,在同一个班的学生里,指定一个老大(t),当查询两个学生(x,y)时,只需要看者两个学生是否与老大间接认识或直接认识,如果都认识,那么者两个学生就在同一个班里。
给出条件:
1号与2号是同学
3号与4号是同学
5号与2号是同学
4号与6号是同学
2号与6号是同学
8号与7号是同学
9号与7号是同学
1号与6号是同学
2号与4号是同学
最开始,所有人的同学都是自己(似乎没毛病)。数组father代表的是每一位同学箭头所指
的同学,也就是与其呈直接认识关系的另一位同学(有点绕)。
下面,我们要让1和2建立同学关系,让2当1的老大。
2已经成功当上了1的老大,我们让4也称为3的老大。
下面我们让6把4和他的小弟收编了,让2成为5的老大。
现在6又把2和他的小弟收编了。
下面8和9投靠了7。
下面1和6建立直接认识关系,2和4页建立直接认识关系。
这就是并查集的基本过程,下面是代码部分。
下面是并查集通用代码。
- void init(int n)
- {
- for(int i=1; i<=n; ++i)
- {
- father[i]=i;
- //最开始,每个人只和自己是直接认识的,也就是说自己是自己的老大
- }
- }
- int find(int x)
- {
- //如果x是自己的同伴,那x就是这个队伍的老大,返回其本身即可。
- if(father[x]==x)
- {
- return x;
- }
- //否则就继续寻找x的老大father[x],看father[x]的老大是谁
- else
- {
- return find(father[x]);
- }
- }
- //合并x和y所在的队伍
- int combine(int x,int y)
- {
- //p为x所在队伍的老大
- //q为y所在队伍的老大
- int p=find(x);
- int q=find(y);
- if(p==q)
- {
- //两者在同一个队伍中
- return 0;
- }
- //将x所在的队伍p合并到q的队伍中
- else
- {
- father[p]=q;
- return 1;
- }
- }

题目链接在最前面
这道题说白了就是要判断两个学生的老大是不是同一个人,其实很简单,只需要用到这个
if(find(x)==find(y))
但是注意,一个人只能有一个老大,所以当有a已经拥有老大s,而来做b的小弟时,s成为b的小弟。
上代码!
- #include <bits/stdc++.h>
- using namespace std;
- int n,m,father[10005];
- int find(int x)//这个函数前面说到过
- {
- if(father[x]==x) return x;
- return father[x]=find(father[x]);
- }
- void combine(int x,int y)//这个也一样
- {
- int fax=find(x),fay=find(y);
- if(fax!=fay)
- {
- father[fax]=fay;
- }
- }
- int main()
- {
- cin>>n>>m;
- for(int i=1; i<=n; i++)
- {
- father[i]=i;
- }
- for(int i=1; i<=m; i++)
- {
- int x,y,z;
- cin>>z>>x>>y;
- if(z==1)
- {
- combine(x,y);
- }
- else
- {
- if(find(x)==find(y))
- {
- cout<<"Y"<<endl;
- }
- else
- {
- cout<<"N"<<endl;
- }
- }
- }
- return 0;
- }

小试牛刀一下,很简单对吧QWQ
这道题,我们没输入两个村庄,就把它们连起来。如果遇到没有老大的村庄(祖先是没有老大的),就是遇到了一个需要建设的村庄。
注意:最终答案要-1
猜猜为啥?三个点,做成连通图,要几条线?两条对不对。四个点就要三条线,所以最终答案-1。
上代码!
- #include <bits/stdc++.h>
- using namespace std;
- int fa[1000001], n, m, x, y;
- int find(int x)
- {
- if(x!=fa[x])//当x不等于它的老大时(当它是祖先时,它没有老大)
- {
- fa[x]=find(fa[x]);//继续找他的老大的老大
- }
- return fa[x];//返回祖先
- }
- void combine(int x, int y)
- {
- int r1=find(x);//寻找祖先
- int r2=find(y);
- fa[r1]=r2;//祖先和祖先结为老大(谁是老大谁是儿子都可以)
- }
- int main()
- {
- while(1)
- {
- int ans=0;
- cin>>n;
- if(n==0)
- {
- return 0;
- }
- cin>>m;
- for(int i=1; i<=n; i++)//初始化
- {
- fa[i]=i;
- }
- for(int i=1; i<=m; i++)
- {
- cin>>x>>y;
- combine(x, y);
- }
- for(int i=1; i<=n; i++)
- {
- if(find(i)==i)//自己的老大就是自己本身
- {
- ans++;
- }
- }
- printf("%d\n", ans - 1);
- }
- return 0;
- }

这道题思路很简单。两个洞如果相交或相切,就编入同一个队伍中,一个队伍就是一个通道。只需要判断每个通道是否存在元素与底部、顶部连接即可。
那怎么判断两个圆是否相交呢?如果两个圆半径之和大于或等于两个圆圆心的距离,那么两个圆相交。
上代码!
- #include<bits/stdc++.h>
- using namespace std;
- int father[1001];
- int find(int x)
- {
- if (x!=father[x]) father[x]=find(father[x]);
- return father[x];
- }
- long long dis(long long x,long long y,long long z,long long x1,long long y1,long long z1)
- {
- return (x-x1)*(x-x1)+(y-y1)*(y-y1)+(z-z1)*(z-z1);
- }//两点距离公式
- long long x[100001],y[100001],z[100001];
- int f1[100001],f2[100001];//f1记录与顶面相交的洞的序号,f2记录与底面相交的洞的序号
- int main(){
- int t;
- cin>>t;
- int n,h;
- long long r;
- for(int i=1;i<=t;i++)
- {
- cin>>n>>h>>r;
- int tot1=0;//记录与顶面相交的洞有几个
- int tot2=0;//记录与底面相交的洞有几个
- for(int j=1;j<=n;j++)
- {
- father[j]=j; //并查集初始化
- }
- for (int j=1;j<=n;j++)
- {
- cin>>x[j]>>y[j]>>z[j];
- if(z[j]+r>=h)
- {
- tot1++;
- f1[tot1]=j;
- }
- if(z[j]-r<=0)
- {
- tot2++;
- f2[tot2]=j;
- }
- for (int k=1;k<=j;k++)//枚举之前的洞是否与这个洞相交,如果相交则合并集合
- {
- if ((x[j]-x[k])*(x[j]-x[k])+(y[j]-y[k])*(y[j]-y[k])>4*r*r) continue;//防止爆long long的特判。
- if (dis(x[j],y[j],z[j],x[k],y[k],z[k])<=4*r*r)
- {
- int a1=find(j);
- int a2=find(k);
- if (a1!=a2) father[a1]=a2;
- }
- }
- }
- int s=0;
- //看看每一个中是否有洞连接上下面
- for(int j=1;j<=tot1;j++)
- {
- for(int k=1;k<=tot2;k++)
- {
- if(find(f1[j])==find(f2[k]))
- {
- s=1;
- break;
- }
- }
- if(s==1) break;
- }
- if(s==1) cout<<"Yes"<<endl;
- else cout<<"No"<<endl;
- }
- return 0;
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。