洛谷题单指南-最短路-P6464 [传智杯 #2 决赛] 传送门
原题链接:https://www.luogu.com.cn/problem/P6464
题意解读:将任意两点连一条权值为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分代码:
#include <bits/stdc++.h>
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;
}
浙公网安备 33010602011771号