题目链接
A 通信系统
- 当所有端点都在一个集合中且没有形成环,即所有端点形成一棵树,则是符合要求的。故需要判断是否有环,判断最后并查集的个数是否为 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 。参考代码如下。
#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
- 跟 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
- 一开始读了半天题不知道什么意思,后来看了其他题解才明白。就是有多个并查集,求元素最多的集合的元素个数,只需在合并的时候把元素个数也合并下就可以了。注意 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;
}