题目描述
在冰岛,你的某个朋友是你的亲戚,为此有个APP就是可以测算出你和你的ta是否带有血缘关系。他可能是你的曾祖父的外公的女婿的外甥女的表姐的孙子。此时,如果能得到完整的家谱,判断两个人是否是亲戚应该是可行的,但如果两个人的最近公共祖先与他们相隔好几代,使得家谱十分庞大,那么检验亲戚关系实非人力所能及。在这种情况下,就可以借助计算机编程来解决这个问题。为了将问题简化,你将得到一些亲戚关系的信息,比如小奇和小明是亲戚,小明和阿珂是亲戚,等等。从这些信息中,你可以推出小奇和阿珂是亲戚。请你编写一个程序,对于我们的关于亲戚关系的提问,以最快的速度给出答案。
输入
输入由两部分组成。
第一部分以N,M开始。N为问题涉及的人的个数(1≤N≤20000)。这些人的编号为1,2,3,…, N。下面有M行(1≤M≤1000000),每行有两个数ai,bi,表示已知ai和bi是亲戚。
第二部分以Q开始。以下Q行有Q个询问(1≤ Q ≤1000000),每行为ci,di,表示询问ci和di是否为亲戚。
输出
对于每个询问ci,di,输出一行:若ci和di为亲戚,则输出“Yes”,否则输出“No”。
一道最基础的并查集应用
first:初始化
for(int i=1;i<=n;i++){
p[i]=i;
cnt[i]=1;
}
//p[i]就代表i的父节点
//cnt[i]是统计每个家族人数,在本题中无用,可删去cnt数组
second:输入&加入家族
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
join(a,b);
}
//下面就是join数组
void join(int x,int y){
int x1=findth(x);
int y1=findth(y);
if(x1!=y1){
p[x1]=y1;
cnt[y1]+=cnt[x1];
}
}
findth函数:
int findth(int x){
if(x==p[x])
return x;
else{
return p[x]=findth(p[x]);
}
}
(findth是用来寻找x的祖先节点,因为x父节点不一定能是此家族祖先
third:输出部分
int q;
scanf("%d",&q);
for (int i=1;i<=q;i++){
int a,b;
scanf("%d%d",&a,&b);
if (findth(p[a])==findth(p[b])){
printf("Yes\n");
}else{
printf("No\n");
}
}
完整(AC)代码奉上,为防止ctrl+c行为,此AC代码中有一些语法错误,需在自己理解情况上自行写出
# include <iostream>
# include <cstdion>
using namespace std;
const int maxm=1000001;
const int maxn=20001;
int p[maxn];
int cnt[maxn];
int findth(int x){
if(x==p[x])
return x;
else{
return p[x]=findth(p[x]);
}
}
void join(int x,int y){
int x1=findth(x);
int y1=findth(y);
if(x1!=y1){
p[x1]=y1;
cnt[y1]+=cnt[x1];
}
return 0;
}
int main(){
int n,m;
scanf("%d%d",n,m);
for(int i=1;i<=n;i++){
p[i]=i;
cnt[i]=1;
}
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",a,b);
join(a,b);
}
int q;
scanf("%d",&q);
for (int i=1;i<=q;i++){
int a,b;
scanf("%d%d",a,b);
if (findth(p[a])==findth(p[b])){
printf("Yes\n");
}else{
printf("No\n");
}
}
return 0;
}
结尾:
感谢观看
制作不易给个免费的赞吧~