亲戚(并查集)
题目描述
题目背景: 若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。 题目描述: 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚。如果x,y是亲戚,那么x的亲戚都是y的亲戚,y的亲戚也都是x的亲戚。
输入输出样例
样例1 请点击题目链接查看
样例2 是我下载的一组数据
输入:
10 20 10
10 5
5 6
2 9
4 2
4 9
8 5
4 6
5 1
9 1
5 1
6 5
6 1
3 10
8 9
4 1
2 6
2 9
4 9
3 7
1 3
9 4
6 8
8 3
3 8
8 3
8 10
3 2
8 10
3 1
1 2
输出:全部为Yes
解题思路
很明显是个并查集,并查集主要涉及到两种操作,合并和查找。 在这个题中,就是若两个人x,y有亲戚关系,那么就把 x 的祖先作为 y 的祖先的爸爸。这样,对于这两个人,在查询他们的最终祖先时,查询结果就是相同的(都是 x 的祖先)。那么我们最终判断两个人是否有亲戚关系时,就可以通过判断他们的最终的祖先是否相同来判断。
代码如下
#include<bits/stdc++.h>
using namespace std;
int fa[5050];
int find(int x){ //查找某人最终祖先,这是一个递归,截至条件就是当找到了一个人的祖先就是他自己,那么就找到了最终的祖先。
if(fa[x] == x) return x;
return fa[x] = find(fa[x]);//这步可以简化递归,在查询时,同时存储了这一个人的祖先是谁,这样在之后查询时,就不用查询到最后了。
}
int main() {
int n,m,p;
scanf("%d%d%d",&n,&m,&p);
for(int i = 1; i<= n; i++) fa[i] = i; //初始化每个人的祖先都是他自己,作为独立的节点,之后再通过合并连接节点。
int mi,mj;
while(m--) {
scanf("%d%d",&mi,&mj);
int x = find(mi);
int y = find(mj);
if(x!=y) fa[y] = x;//合并,将mj的祖先的父亲节点设置为mi的祖先节点。在图中,其实就是将mi,mj的祖先连起来,将mi的祖先作为mi和mj的最终的祖先。
}
int pi,pj;
while(p--) {
scanf("%d%d",&pi,&pj);
int x = find(pi);
int y = find(pj);
if(x == y) printf("Yes\n");
else printf("No\n");
}
}