题目
若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。规定:x 和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。
输入输出格式
输入格式
第一行:三个整数n,m,p,(n,m,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
解析
这个题目将所有有亲戚关系的人归位同一个集合中(同一个家族)。如果想查询两个人是否具有亲属关系,只需要判断这两个人是否为同一个家族内。
判断两个人是否是在同一个家族内时,每个家族中选出一位族长来代表整个家族,这样只需要直到两个人的族长是否为同一人,就能判断出是否属于同一个家族。根据输入的一对对关系来建立这个家族关系,之后就知道每位成员的族长是谁。
如果需要查询两个人是否在同一个家族中,只需要查询这两个人的族长是否是同一人,如果要把两个家族合并,就把其中一个家族的族长的负责人指向另外一个家族的族长即可。这种处理不相交可合并的数据结构叫做并查集。并查集具有查询、合并这两种基本操作。
#include<iostream>
#define maxn 5010
using namespace std;
int n,m,p,x,y;
int fa[maxn];
int find(int x){//查询是否是同一个集合if(x==fa[x]){return x;}return fa[x]=find(fa[x]);
}
void join(int c1,int c2){//连接两个集合int f1=find(c1),f2=find(c2);if(f1!=f2){fa[f1]=f2;}
}
int main(){cin>>n>>m>>p;for(int i=1;i<=n;i++){fa[i]=i;//初始化,自己是自己的族长}for(int i=0;i<m;i++){cin>>x>>y;join(x,y);}for(int i=0;i<p;i++){cin>>x>>y;if(find(x)==find(y)){cout<<"Yes"<<endl;}else{cout<<"No"<<endl;}}return 0;
}