洛谷题单指南-最短路-P6464 传智杯 决赛 传送门
原题链接: www.luogu.com.cn/problem/P64… 题意解读: 将任意两点连一条权值为0的边,计算所有不同两点最短路之和的最小值。 解题思路: 1、朴素想法 枚举所有可能连0边的两点(O(n^2)),建立0边之后跑Floyd算法(O(n^3)),然后更新答案。 总体复杂度为O(n^5),需要进行优化。 2、优化方法 对于每一次两点建0边,都跑一遍完整的Floyd算法,是比较浪费的! 因为Floyd会更新所有两点之间的最短路,而两点建0边,只会影响经过这两点的所有路径的最短路。 所以跑Floyd时没有必要枚举所有的中间点,只需要固定建0边的2个点,更新经过这两个点的所有路径的最短路即可! 这样复杂度可以优化到O(n^4)。 100分代码: ```
洛谷题单指南-最短路-P6464 传智杯 决赛 传送门
using namespace std;
const int N = 205; int d[N][N], b[N][N]; int n, m;
int main() { memset(d, 0x3f, sizeof(d)); cin >> n >> m; while(m--) { int u, v, w; cin >> u >> v >> w; d[u][v] = d[v][u] = w; } for(int i = 1; i <= n; i++) { d[i][i] = 0; }
for(int k = 1; k <= n; k++)
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
int ans = 2e9;
//枚举所有可能的传送门
for(int x = 1; x < n; x++)
{
for(int y = x; y <= n; y++)
{
memcpy(b, d, sizeof(d)); //把d复制一份到b
b[x][y] = b[y][x] = 0; //传送门对应的路径长度置为0
//对于经过传送门中点x的最短路进行floyd操作
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
b[i][j] = min(b[i][j], b[i][x] + b[x][j]);
//对于经过传送门中点y的最短路进行floyd操作
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
b[i][j] = min(b[i][j], b[i][y] + b[y][j]);
//更新一次答案
int res = 0;
for(int i = 1; i < n; i++)
for(int j = i + 1; j <= n; j++)
res += b[i][j];
ans = min(ans, res);
}
}
cout << ans;
return 0;
}
> 原文链接: https://www.cnblogs.com/jcwy/p/18822385