题解:洛谷 P14077 连通图
【题目来源】
洛谷:P14077 [GESP202509 七级] 连通图 - 洛谷
【题目描述】
给定一张包含 \(n\) 个结点与 \(m\) 条边的无向图,结点依次以 \(1,2,…,n\) 编号,第 \(i\) 条边(\(1≤i≤m\))连接结点 \(u_i\) 与结点 \(v_i\)。如果从一个结点经过若干条边可以到达另一个结点,则称这两个结点是连通的。
你需要向图中加入若干条边,使得图中任意两个结点都是连通的。请你求出最少需要加入的边的条数。
注意给出的图中可能包含重边与自环。
【输入】
第一行,两个正整数 \(n,m\),表示图的点数与边数。
接下来 \(m\) 行,每行两个正整数 \(u_i,v_i\),表示图中一条连接结点 \(u_i\) 与结点 \(v_i\) 的边。
【输出】
输出一行,一个整数,表示使得图中任意两个结点连通所需加入的边的最少数量。
【输入样例】
4 4
1 2
2 3
3 1
1 4
【输出样例】
0
【核心思想】
-
问题分析:给定一张包含 \(n\) 个结点和 \(m\) 条边的无向图(可能含重边与自环),要求通过添加最少的边,使得图中任意两个结点都连通。本质是求原图的连通分量个数,若连通分量个数为 \(k\),则最少需要添加 \(k-1\) 条边将它们连成一棵树。
-
算法选择:
- 并查集(Union-Find):动态维护结点的连通关系,支持高效的合并与查询。
- 路径压缩:在查找根节点时压缩路径,使后续查询接近 \(O(1)\)。
- 连通分量统计:遍历所有结点,统计不同根节点的数量,即为连通分量个数。
-
关键步骤:
- 初始化:将每个结点的父节点设为自身。
- 合并边:对于每条边 \((u, v)\),执行
union(u, v),即p[find(u)] = find(v),将两个端点所在集合合并。重边和自环不影响合并结果。 - 统计连通分量:遍历 \(i = 1 \dots n\),找到每个结点的根节点,用标记数组记录出现过的根,统计不同根的个数
cnt。 - 输出答案:
cnt - 1,即需要添加的最少边数。
-
时间/空间复杂度:
- 时间复杂度:\(O(m \alpha(n))\),其中 \(\alpha(n)\) 为反阿克曼函数,近似常数,总效率极高。
- 空间复杂度:\(O(n)\),用于存储并查集父节点数组和标记数组。
-
并查集的核心思想:
- 动态连通性:并查集能快速判断两个元素是否属于同一集合,并高效合并集合。
- 树形结构表示集合:每个集合用一棵树表示,根节点作为集合代表。
- 路径压缩优化:在查找过程中将路径上的结点直接指向根,降低树高。
- 连通分量计数:最终不同根的数量即为连通分量数,连接所有分量成一棵生成树需要 \(\text{分量数} - 1\) 条边。
- 适用于无向图连通性判定、Kruskal 最小生成树、网络连通等场景。
【算法标签】
普及- #并查集
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100005; // 定义最大节点数
int n; // 节点数量
int m; // 边数量
int ans = 0; // 存储连通分量数量
int p[N]; // 并查集父节点数组
bool vis[N]; // 标记数组,记录是否已统计过该连通分量
/**
* 并查集查找函数(带路径压缩)
* @param x 要查找的节点
* @return 节点x的根节点
*/
int find(int x)
{
if (p[x] != x) // 如果当前节点不是根节点
{
p[x] = find(p[x]); // 路径压缩
}
return p[x];
}
int main()
{
// 输入节点数和边数
cin >> n >> m;
// 初始化并查集,每个节点的父节点指向自己
for (int i = 1; i <= n; i++)
{
p[i] = i;
}
// 处理每条边,合并连通分量
while (m--)
{
int a, b;
cin >> a >> b;
// 合并a和b所在的连通分量
p[find(a)] = find(b);
}
// 统计连通分量数量
for (int i = 1; i <= n; i++)
{
int x = find(i); // 找到节点i的根节点
if (!vis[x]) // 如果该连通分量未被统计过
{
ans++; // 连通分量数量加1
vis[x] = 1; // 标记该连通分量已统计
}
}
/**
* 输出结果:
* 连通分量数量减1,即需要添加的边数
* 因为要将所有连通分量连接成一棵树需要ans-1条边
*/
cout << ans - 1 << endl;
return 0;
}
【运行结果】
4 4
1 2
2 3
3 1
1 4
0
浙公网安备 33010602011771号