并查集解决洛谷P1551亲戚

亲戚(并查集)

题目链接

题目描述

题目背景: 若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。 题目描述: 规定: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");
	}
} 

猜你喜欢

转载自blog.csdn.net/weixin_43966538/article/details/106538109