定义图有:n个点,m条边 。
这Floyd算法是处理多源最短路的算法,可以应对边权为负的情况,但不能处理负环。
时间复杂度是 O ( n 3 ) O(n^3) O(n3)
floyd是基于动态规划的思路实现的。
d [ k , i , j ] d[k, i, j] d[k,i,j]表示从点 i i i出发,只经过 1 , 2 , . . . , k 1, 2,...,k 1,2,...,k的中间点,到达 j j j的最短距离,设这条路径为 p p p。
假设我们已经有了所有的 d [ k − 1 , x , y ] d[k-1, x, y] d[k−1,x,y],现在想要求 d [ k , i , j ] d[k, i, j] d[k,i,j]。
综上可以得到递推式:
d [ k , i , j ] = d [ k − 1 , i , k ] + d [ k − 1 , k , j ] d[k, i, j] = d[k-1, i, k] + d[k-1, k, j] d[k,i,j]=d[k−1,i,k]+d[k−1,k,j]
d d d的第一维 k k k可以用滚动数组去掉,只用保留后两维。
由递推顺序,先知道k-1才能知道k,因此k循环放在最外面
注意这题边权可能为负,哪怕不存在路径,dis[i]=INF也可能被更新,会比INF更小,不能直接判断dis[i] = INF,可以判断dis[i] > INF / 2输出impossible。
此外该题有自环,因为不存在负环,因此没有负自环,那么走自环肯定不如不走,要将dis[i][i]
置为0。
#include
using namespace std;
const int N = 205, M = 20005, INF = 0x3f3f3f3f;
int n, m, k;
int dis[N][N];
void floyd() {
for (int k = 1; k <= n; k ++ ) {
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= n; j ++ ) {
dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
}
}
}
}
int main() {
scanf("%d%d%d", &n, &m, &k);
int u, v, w;
for (int i = 1; i <= n; i ++ ) {
for (int j = 1; j <= n; j ++ ) {
if (i == j) dis[i][j] = 0; // 自环为0
else dis[i][j] = INF;
}
}
while (m --) {
scanf("%d%d%d", &u, &v, &w);
dis[u][v] = min(w, dis[u][v]); // 重边留最小
}
floyd();
while (k -- ) {
scanf("%d%d", &u, &v);
if (dis[u][v] > INF / 2) printf("impossible\n");
else printf("%d\n", dis[u][v]);
}
return 0;
}