题目描述 :有 n 个城市(编号 1 ~ n)和 m 条双向道路。每条道路连接两个城市。现在要判断:
-
这些城市是否全部连通(即任意两个城市之间都有路径)。
-
如果全部连通,输出
YES;否则输出需要最少新增多少条道路才能全部连通。
输入:
-
第一行:
n m(1 ≤ n ≤ 10^5,0 ≤ m ≤ 2×10^5) -
接下来
m行:每行两个整数u v,表示一条道路。
输出:
-
若已全部连通:
YES -
否则:一个整数,表示最少新增道路数。
示例:
text
输入:
5 3
1 2
2 3
4 5
输出:
1
解释:连通分量为 {1,2,3} 和 {4,5},需要 1 条路连接两个分量。
解题思路
用并查集维护连通分量:
-
初始每个城市独立,连通分量数
components = n。 -
每合并两个不同集合,
components--。 -
最终若
components == 1,输出YES;否则输出components - 1(最少新增道路数 = 连通分量数 - 1)。
参考代码
c
#include <stdio.h>
int parent[100005];
int rank_[100005];
int find(int x) {
if (parent[x] != x)
parent[x] = find(parent[x]); // 路径压缩
return parent[x];
}
int unite(int a, int b) {
int ra = find(a), rb = find(b);
if (ra == rb) return 0;
if (rank_[ra] < rank_[rb]) {
parent[ra] = rb;
} else if (rank_[ra] > rank_[rb]) {
parent[rb] = ra;
} else {
parent[rb] = ra;
rank_[ra]++;
}
return 1;
}
int main(void) {
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
parent[i] = i;
rank_[i] = 0;
}
int components = n;
for (int i = 0; i < m; i++) {
int u, v;
scanf("%d %d", &u, &v);
if (unite(u, v)) components--;
}
if (components == 1)
printf("YES\n");
else
printf("%d\n", components - 1);
return 0;
}