1 条题解
-
0
解题思路:最小生成树中的最长边问题
1. 问题理解
我们需要在给定的城镇网络中找到一种高速公路修建方案,使得:
- 所有城镇都能互相连通(形成连通图)
- 所有修建的高速公路中最长的那条要尽可能短
这实际上是要找到图的最小生成树(Minimum Spanning Tree, MST),然后找出这个生成树中最长的边。
2. 算法选择
使用Prim算法来求解最小生成树,因为:
- 适合稠密图(城镇数量N≤500,是完全图)
- 时间复杂度O(N²)在本题数据范围内可行
- 可以方便地记录生成树中的所有边权
3. 具体实现步骤
-
输入处理
- 读取测试用例数量T
- 对每个测试用例:
- 读取城镇数量N
- 读取N×N的距离矩阵
-
Prim算法初始化
- 将每个城镇到自己的距离设为INF(不可达)
- 初始化lowcost数组,记录从已选城镇到未选城镇的最小距离
- 初始化vis数组标记城镇是否已加入生成树
- 从第一个城镇开始构建生成树
-
构建最小生成树
- 每次循环: a. 在未选择的城镇中,找到距离当前生成树最近的城镇 b. 将该城镇加入生成树 c. 记录这条边的权值 d. 更新其他未选城镇到生成树的最小距离
-
寻找最长边
- 在生成树的所有边中,找出权值最大的那条
-
输出结果
- 对每个测试用例,输出生成树中最长边的长度
4. 关键点说明
- 距离矩阵处理:对角线元素设为INF,避免自环
- 贪心策略:Prim算法每次选择最短的边加入生成树
- 最长边记录:在构建生成树时保存所有边的权值,最后找出最大值
- 输入优化:使用scanf提高读取速度(题目提示输入量较大)
5. 复杂度分析
- 时间复杂度:O(T×N²),其中T是测试用例数,N是城镇数
- 空间复杂度:O(N²)存储距离矩阵
6. 示例解析
以题目中的样例输入为例:
3 0 990 692 990 0 179 692 179 0
算法执行过程:
- 从城镇1开始
- 选择最短边1-3(692)
- 然后选择3-2(179)
- 生成树包含两条边692和179
- 最长边是692
7. 为什么这样做是正确的?
根据最小生成树的性质:
- 所有生成树中,Prim算法得到的生成树总权值最小
- 在这个最小的总权值生成树中,最长边也是所有可能生成树中最长边里最小的
- 这正好符合题目"最小化最长公路"的要求
标程
#include <cstdio> // 使用C++标准库的stdio #include<iostream> #define MAX 500 // 最大城市数量 #define INF 0x3f3f3f3f // 定义一个很大的数表示无穷大 int a[MAX][MAX]; // 城市间的距离矩阵 int lowcost[MAX]; // 记录最小生成树的最小边权 int vis[MAX]; // 记录城市是否被访问过 int b[MAX]; // 存储最小生成树的边权 int main() { int ExampleNumber; // 测试用例数量 int N; // 城市数量 int i, j, k; // 循环变量 int maxx; // 最长公路长度 int minn; // 临时最小值 // 读取测试用例数量 scanf("%d", &ExampleNumber); // 处理每个测试用例 while (ExampleNumber--) { // 读取城市数量 scanf("%d", &N); // 读取城市间距离矩阵 for (i = 1; i <= N; i++) { for (j = 1; j <= N; j++) { scanf("%d", &a[i][j]); } } // 初始化 for (i = 1; i <= N; i++) { a[i][i] = INF; // 城市自己到自己的距离设为无穷大 lowcost[i] = a[1][i]; // 初始化从城市1到其他城市的距离 vis[i] = 0; // 所有城市初始未访问 } vis[1] = 1; // 从城市1开始 // Prim算法求最小生成树 for (i = 1; i < N; i++) { minn = INF; // 找出当前未访问城市中距离最小的 for (j = 1; j <= N; j++) { if (minn > lowcost[j] && vis[j] == 0) { minn = lowcost[j]; k = j; // 记录最小距离的城市 } } vis[k] = 1; // 标记为已访问 b[i] = minn; // 存储这条边的权值 // 更新lowcost数组 for (j = 1; j <= N; j++) { if (vis[j] == 1) { lowcost[j] = INF; // 已访问的城市设为无穷大 } if (vis[j] == 0 && a[k][j] < lowcost[j]) { lowcost[j] = a[k][j]; // 更新到未访问城市的最小距离 } } } // 找出最小生成树中最长的边 maxx = 0; for (i = 1; i < N; i++) { if (maxx < b[i]) { maxx = b[i]; } } // 输出结果 printf("%d\n", maxx); } return 0; }
- 1
信息
- ID
- 1486
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 6
- 已通过
- 1
- 上传者