洛谷 P1551 亲戚

题目链接:

https://www.luogu.com.cn/problem/P1551icon-default.png?t=N7T8https://www.luogu.com.cn/problem/P1551


题目:

若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系。

规定:x 和 y 是亲戚,y 和 z 是亲戚,那么 x 和 z 也是亲戚。如果 x,y 是亲戚,那么 x 的亲戚都是 y 的亲戚,y 的亲戚也都是 x 的亲戚。

输入格式:

第一行:三个整数 n,m,p(n,m,p≤5000),分别表示有 n 个人,m 个亲戚关系,询问 p 对亲戚关系。

以下 m 行:每行两个数 eq?M_%7Bi%7D ​,eq?M_%7Bj%7D,1≤​ eq?M_%7Bi%7D , eq?M_%7Bj%7D ≤n,表示  和 ​ 具有亲戚关系。

接下来 p 行:每行两个数 eq?P_%7Bi%7D , eq?P_%7Bj%7D ,询问 eq?P_%7Bi%7D​ 和 eq?P_%7Bj%7D 是否具有亲戚关系。

输出格式:

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


思路:

这是一道典型的并查集题,我们可以直接使用并查集的模板。

class Union {
	public:
		Union(int n) :fa(n + 1) {
			for (int i = 0; i < n; i++) {
				fa[i] = i;
			}
		}
		int find(int i) {
			return fa[i] = (fa[i] == i ? i : find(fa[i]));
		}
		void merge(int x, int y) {
			if (find(x) == find(y)) {
				return;
			}
			fa[find(x)] = find(y);
			return;
		}
		vector<int> fa;
};

首先读入n,m分别表示n个人和m种关系。让并查集开辟一个大小为(n+1)的数组,并且让并查集中的每一个元素等于他在数组中的序号,用于一开始表示没关系的各人。

接下来循环m次,读入有关系的俩人,使用并查集中的merge将俩人关系起来。

最后,循环p次,使用Union类中的find来判断俩人是否有关系,若find返回的结果相同,则表示俩人有关系,输出Yes;否则输出No。


AC代码:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>

using namespace std;

class Union {
	public:
		Union(int n) :fa(n + 1) {
			for (int i = 0; i < n; i++) {
				fa[i] = i;
			}
		}
		int find(int i) {
			return fa[i] = (fa[i] == i ? i : find(fa[i]));
		}
		void merge(int x, int y) {
			if (find(x) == find(y)) {
				return;
			}
			fa[find(x)] = find(y);
			return;
		}
		vector<int> fa;
};

int n, m, p;

int main() {

	scanf("%d%d%d", &n, &m, &p);
	Union u(n);
	while (m--) {
		int num1, num2;
		scanf("%d%d", &num1, &num2);
		u.merge(num1, num2);
	}
	while (p--) {
		int num1, num2;
		scanf("%d%d", &num1, &num2);
		if (u.find(num1) == u.find(num2)) {
			printf("Yes\n");
		}
		else {
			printf("No\n");
		}
	}

	return 0;
}

如果我的文章对你有所帮助,不妨给我个关注何点赞吧。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值