洛谷P1111题解:修复公路问题的最优解法
一、问题描述
给定N个村庄和M条公路,每条公路连接两个村庄并有修复时间t。求最早什么时候所有村庄可以连通,如果不能连通则输出-1。
二、算法核心思想
使用并查集管理村庄连通性
按修复时间排序所有公路
依次选择最短修复时间的公路进行连接
当所有村庄连通时输出最大修复时间
三、完整代码实现(带详细注释)
#include <iostream> #include <algorithm> #include <vector> using namespace std; // 定义公路结构体 struct Edge { int u, v, t; // u和v表示连接的村庄,t表示修复时间 bool operator<(const Edge& other) const { return t < other.t; // 按修复时间排序 } }; vector<int> parent; // 并查集父节点数组 // 查找根节点(带路径压缩) int find(int x) { return parent[x] == x ? x : parent[x] = find(parent[x]); } // 合并两个集合 bool unite(int x, int y) { x = find(x); y = find(y); if(x == y) return false; // 已经在同一集合 parent[y] = x; // 合并 return true; } int main() { int N, M; // N个村庄,M条公路 cin >> N >> M; vector<Edge> edges(M); // 存储所有公路 parent.resize(N+1); // 初始化并查集 // 初始化每个村庄的父节点为自己 for(int i=1; i<=N; i++) parent[i] = i; // 输入公路信息 for(int i=0; i<M; i++) cin >> edges[i].u >> edges[i].v >> edges[i].t; // 按修复时间排序 sort(edges.begin(), edges.end()); int cnt = 0, max_t = 0; // cnt记录已连接边数,max_t记录最大时间 for(auto& e : edges) { if(unite(e.u, e.v)) { // 如果成功连接 max_t = max(max_t, e.t); // 更新最大时间 if(++cnt == N-1) break; // 已连接N-1条边,所有村庄连通 } } // 输出结果:如果连通输出最大时间,否则输出-1 cout << (cnt == N-1 ? max_t : -1) << endl; return 0; }
四、算法分步解析
数据结构准备:
定义Edge结构体存储公路信息
实现并查集的find和unite操作
初始化并查集数组
输入处理阶段:
读取村庄数量和公路数量
存储所有公路信息
按修复时间排序公路
核心算法阶段:
依次处理每条公路
使用并查集判断是否连接新村庄
更新最大修复时间
检查是否所有村庄已连通
结果输出:
根据连通情况输出结果
五、常见误区与调试技巧
忘记初始化并查集数组
路径压缩实现错误
排序标准设置错误
连通性判断条件错误
六、扩展思考
如何优化空间复杂度?
如果要求输出具体修复方案该如何修改?
如何可视化这个连接过程?
如果村庄之间有距离限制该如何处理?
原创内容 转载请注明出处