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

30 篇文章 0 订阅
8 篇文章 0 订阅

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

题目大意:

给你一些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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值