题目概述:
现有Flatopia这个地方的政府打算修建公路,打算修建的公路应该能够满足从一个地点一定能到达另一个地点,政府的目的是在保证任意一个城镇均能从其他任意城镇到达的前提下,要使修建的那条最长公路的长度最小。
翻译一下,就是连通图(保证任意一个城镇均能从其他任意城镇到达),求最小生成树(公路)的最大边(最长公路)。
算法思想:
用最小生成树中的prim算法,按照prim算法遍历图的模式,一步一步得到最后的结果。
prim算法模板中,本来res代表的是最小生成树的长度,如今改一下更新条件,便可以记录下来最小生成树的最大边了。
代码部分:
#include <iostream> #include <stdio.h> #include <string> #include <string.h> #include <map> #include <cmath> #include <algorithm> using namespace std; int n, t; const int INF = 10000000; int cost[517][517]; // 关系矩阵,记录权值 bool used[517]; // 这个点是否被加入集合 int min_cost[517]; // 从之前集合到这个点i的最短距离 // prim 算法 int prim() { for (int i = 0; i < n; i++) { min_cost[i] = INF; // 初始化所有点,开始集合为空集,所有点的具体自然是无穷 } min_cost[0] = 0; // 首先将起始点距离设为0 int res = 0; // res可以代表很多事情,比如说最小生成树的总权值 // 在这道题就是最小生成树的最大边 while (true) { int v = -1; // 记载加哪个点的过程,统计出当前最小的min_cost[v] // 即此时v点距离集合距离最短 for (int u = 0; u < n; u++) { if (!used[u] && (v == -1 || min_cost[u] < min_cost[v])) v = u; } if (v == -1) break; // 这个条件说明没有新加入点 used[v] = true; res = res > min_cost[v] ? res : min_cost[v]; // 更新res值,即最大边的值 // 因为之前的min_cost是所有点到已有集合的最短值的数组 // 现在我们只需要判断对于新加入的这个点v,最短距离有没有更新即可了 for (int u = 0; u < n; u++) { min_cost[u] = min(min_cost[u], cost[v][u]); } } return res; } int main() { cin >> t; for (int k = 1; k <= t; k++) { cin >> n; memset(used, 0, sizeof(used)); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { scanf("%d", &cost[i][j]); } } cout << prim() << endl; } return 0; }