Contest100000615 - 《算法笔记》9.6小节——数据结构专题(2)->并查集

题目链接

A 通信系统

  1. 当所有端点都在一个集合中且没有形成环,即所有端点形成一棵树,则是符合要求的。故需要判断是否有环,判断最后并查集的个数是否为 1 。参考代码如下。
#include<iostream>
const int maxn = 1010;

using namespace std;

int father[maxn];
bool is_root[maxn];
bool is_circle = false;

void init(int n) {
	for (int i = 1; i <= n; i++) {
		father[i] = i;
		is_root[i] = false;
	}
}

int find_father(int x) {
	int a = x;
	while (x != father[x]) x = father[x];
	while (a != father[a]) {
		int z = a;
		a = father[a];
		father[z] = x;
	}
	return x;
}

void Union(int a, int b) {
	int fa = find_father(a);
	int fb = find_father(b);
	if (fa != fb)
		father[fa] = fb;
	else is_circle = true;
}

int main() {
	int n, m, a, b;
	while (cin >> n >> m && n + m) {
		init(n);
		is_circle = false;
		for (int i = 0; i < m; i++) {
			cin >> a >> b;
			Union(a, b);
		}
		for (int i = 1; i <= n; i++)
			is_root[find_father(i)] = true;
		int cnt = 0;
		for (int i = 1; i <= n; i++)
			cnt += is_root[i];
		if (is_circle || cnt != 1)
			cout << "No" << endl;
		else cout << "Yes" << endl;
	}
	return 0;
}

B 畅通工程

  1. 只需要统计最后的并查集的个数,最少还需要建设的道路数目为并查集的数目减 1 。参考代码如下。
#include<iostream>
const int maxn = 1010;

using namespace std;

int father[maxn];
bool is_root[maxn];

void init(int n) {
	for (int i = 1; i <= n; i++) {
		father[i] = i;
		is_root[i] = false;
	}
}

int find_father(int x) {
	int a = x;
	while (x != father[x]) x = father[x];
	while (a != father[a]) {
		int z = a;
		a = father[a];
		father[z] = x;
	}
	return x;
}

void Union(int a, int b) {
	int fa = find_father(a);
	int fb = find_father(b);
	if (fa != fb)
		father[fa] = fb;
}

int main() {
	int n, m, a, b;
	while (cin >> n >> m && n) {
		init(n);
		for (int i = 0; i < m; i++) {
			cin >> a >> b;
			Union(a, b);
		}
		for (int i = 1; i <= n; i++)
			is_root[find_father(i)] = true;
		int cnt = 0;
		for (int i = 1; i <= n; i++)
			cnt += is_root[i];
		cout << cnt - 1 << endl;
	}
	return 0;
}

C How Many Tables

  1. 跟 B 题一样啦。参考代码如下。
#include<iostream>
const int maxn = 1010;

using namespace std;

int father[maxn];
bool is_root[maxn];

void init(int n) {
	for (int i = 1; i <= n; i++) {
		father[i] = i;
		is_root[i] = false;
	}
}

int find_father(int x) {
	int a = x;
	while (x != father[x]) x = father[x];
	while (a != father[a]) {
		int z = a;
		a = father[a];
		father[z] = x;
	}
	return x;
}

void Union(int a, int b) {
	int fa = find_father(a);
	int fb = find_father(b);
	if (fa != fb)
		father[fa] = fb;
}

int main() {
	int n, m, a, b, t;
	cin >> t;
	while (t--) {
		cin >> n >> m;
		init(n);
		for (int i = 0; i < m; i++) {
			cin >> a >> b;
			Union(a, b);
		}
		for (int i = 1; i <= n; i++)
			is_root[find_father(i)] = true;
		int cnt = 0;
		for (int i = 1; i <= n; i++)
			cnt += is_root[i];
		cout << cnt << endl;
	}
	return 0;
}

D More is better

  1. 一开始读了半天题不知道什么意思,后来看了其他题解才明白。就是有多个并查集,求元素最多的集合的元素个数,只需在合并的时候把元素个数也合并下就可以了。注意 n == 0 时要输出 1 。参考代码如下。
#include<cstdio>
#include<algorithm>
const int maxn = 10000010;

using namespace std;

int father[maxn];
int num[maxn];

void init() {
	for (int i = 1; i < maxn; i++)
		father[i] = i;
	fill(num, num + maxn, 1);
}
int find_father(int x) {
	int a = x;
	while (x != father[x]) x = father[x];
	while (a != father[a]) {
		int z = a;
		a = father[a];
		father[z] = x;
	}
	return x;
}
void Union(int a, int b) {
	int fa = find_father(a);
	int fb = find_father(b);
	if (fa != fb) {
		father[fa] = fb;
		num[fb] += num[fa];
	}
}

int main() {
	int n, a, b;
	while (scanf("%d", &n) != EOF) {
		if (n == 0)
			printf("1\n");
		else {
			init();
			for (int i = 0; i < n; i++) {
				scanf("%d %d", &a, &b);
				Union(a, b);
			}
			int ans = 0;
			for (int i = 1; i < maxn; i++)
				ans = max(ans, num[i]);
			printf("%d\n", ans);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_42717165/article/details/87640943
今日推荐