VK Cup 2017 - Round 1 A - Bear and Friendship Condition(并查集维护大小 + dfs 遍历图统计边数)

该文介绍了一种图的合法性检查问题,要求判断给定的n个点m条边是否构成合法的三元组。解决方案是利用并查集将图分割成若干集合,并对每个集合进行DFS遍历,检查是否为完全图。如果存在一个或两个点满足条件,则图合法。文中还提到了使用集合存储图以优化边数统计的时间复杂度,并提供了相应的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

题目大意:

给你一些n个点m条边,如果三个点(a,b,c)是合法的,当且仅当 a-b,b-c,c-a都有一条边,问你这个图是否合法,如果有一个或两个点视为合法

思路

考虑什么图才是个合法图:除了点数小于 3 的图一定合法外,必须是完全图才合法,假设完全图有 n 个点,则它的边数为:(n - 1) * n / 2。

用并查集分割为若干个集合,dfs 遍历每个集合,判断每个大小大于2的图是否是完全图即可。

这里积累个小技巧,用set存图,每次操作 logn,方便统计图的边数,具体看代码。

时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

代码:

#include<bits/stdc++.h>

using namespace std;
#define int long long
const int N = 1.5e5 + 10;
int n, m;
int p[N], siz[N];
set<int> g[N];
int edge = 0;
bool vis[N];

int Find(int x) {
	if (p[x] != x) {
		p[x] = Find(p[x]);
	}
	return p[x];
}

void dfs(int u)
{
	vis[u] = true;
	edge += g[u].size();
	for (auto son : g[u]) {
		g[son].erase(u);
	}
	for (auto son : g[u]) {
		if (vis[son]) continue;
		dfs(son);
	}
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(nullptr), cout.tie(nullptr);
	cin >> n >> m;
	for (int i = 1; i <= n; ++i) {
		p[i] = i;
		siz[i] = 1;
	}
	for (int i = 0; i < m; ++i) {
		int a, b; cin >> a >> b;
		g[a].insert(b);
		g[b].insert(a);
		int pa = Find(a), pb = Find(b);
		if (pa != pb) {
			siz[pb] += siz[pa];
			p[pa] = pb;
		}
	}
	for (int i = 1; i <= n; ++i) {
		p[i] = Find(i);
	}
	for (int i = 1; i <= n; ++i) {
		if (p[i] != i || siz[i] <= 2) continue;
		edge = 0;
		dfs(i);
		if (edge != siz[i] * (siz[i] - 1) / 2) {
			cout << "NO" << '\n';
			return 0;
		}
	}

	cout << "YES" << '\n';

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值