题目链接:
https://www.luogu.com.cn/problem/P1536https://www.luogu.com.cn/problem/P1536
题目:
某市调查城镇交通状况,得到现有城镇道路统计表。表中列出了每条道路直接连通的城镇。市政府 "村村通工程" 的目标是使全市任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要相互之间可达即可)。请你计算出最少还需要建设多少条道路?
输入格式:
输入包含若干组测试数据,每组测试数据的第一行给出两个用空格隔开的正整数,分别是城镇数目 n 和道路数目 m ;
随后的 m 行对应 m 条道路,每行给出一对用空格隔开的正整数,分别是该条道路直接相连的两个城镇的编号。简单起见,城镇从 1 到 n 编号。
注意:两个城市间可以有多条道路相通。
在输入数据的最后,为一行一个整数 0,代表测试数据的结尾。
输出格式:
对于每组数据,对应一行一个整数。表示最少还需要建设的道路数目。
例:
输入:
4 2 1 3 4 3 3 3 1 2 1 3 2 3 5 2 1 2 3 5 999 0 0
输出:
1 0 2 998
提示:
对于 100% 的数据,保证 1 ≤ n < 1000 。
思路:
这是一个典型的并查集题。我们可以直接拿出并查集的模板。
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;
};
由于此题有若干组输入数据(不定量),所以我们用一个while循环来持续接收输入数据。根据题意,当输入0时程序停止,所以我们设置一个特判,当输入的第一个数组为0时,使用break跳出永真循环。
若n不为0时,接着接收数据m,用于表示有m条道路。然后我们循环m次,使用Union类中的merge将输入的两个城市连通。
然后,我们定义一个整形res用于存储还需要多少条道路才能相互连通。最后,循环n次,用Union类中的find函数来判断该城市是否与其他城市连通,若没有与其他城市连通,则res加一;否则res不变。
最后输出res-1即可。
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] == 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;
int main() {
while (1) {
scanf("%d", &n);
if (n == 0) {
break;
}
scanf("%d", &m);
Union u(n);
while (m--) {
int num1, num2;
scanf("%d%d", &num1, &num2);
u.merge(num1, num2);
}
int res = 0;
for (int i = 1; i <= n; i++) {
if (u.find(i) == i) {
res++;
}
}
printf("%d\n", res - 1);
}
return 0;
}
如果我的文章对你有所帮助,不妨给我个关注何点赞吧。