前面Dijkstra算法和Bellman-Ford算法解决了单源最短路径问题,但是如果需要获取图中任意两顶点的最短
距离呢?我们可以使用前面两个算法我们可以遍历每个顶点得到每个顶点的单源最短距离,但是最短路径算法中
提供了一种更为简单的算法帮助我们实现任意两顶点最短距离(Floyd)。
Floyd算法又称为插点法,是一种利用动态规划的思想寻找给定的加权图中多源点之间最短路径的算法,与Dijkstra算法类似。 该算法名称以创始人之一、1978年图灵奖获得者、斯坦福大学计算机科学系教授
核心思路使用邻接矩阵G来表示图,初始化G,将不可直达的顶点初始化为无穷大,定义k结点,遍历N个顶点->k,使用k作为任意两顶点i,j之间的中介点,
如果G[i][j]>G[i][k] G[k][j],则执行松弛操作,这里我们就可以理解为什么叫插点法了,将每一个顶点当作中介点放入任意两顶点之间,
如果可以执行松弛操作,则进行松弛。
推导过程V0->V1 1
V0->V2 2
V1->V2 -1
初始化图G,执行如下操作
第一轮:
第一步:选取V0作为中介点
第二步:插入任意两顶点之间
首先插入V0->V0之间,G[0][0]>G[0][0] G[0][0],(0>0不满足)无需松弛,
再插入V0->V1之间,G[0][1]>G[0][0] G[0][1],(1>0 1不满足)无需松弛,
再插入V0->V2之间,G[0][2]>G[0][0] G[0][2],(2>0 2不满足)无需松弛。
首先插入V1->V0之间,G[1][0]>G[1][0] G[0][0],(∞>∞ 0不满足)无需松弛,
再插入V1->V1之间,G[1][1]>G[1][0] G[0][1],(∞>∞ 1不满足)无需松弛,
再插入V1->V2之间,G[1][2]>G[1][0] G[0][2],(∞>∞ 2不满足)无需松弛。
......
第二轮在选取V1作为中介点,重复上面操作(这一轮会松弛 G[0][2]>G[0][1] G[1][2]->2>1 (-1) 满足条件,松弛)
第二轮在选取V2作为中介点,重复上面操作
最终得到最短路径
实现代码//
// main.cpp
// Floyd
//
// Created by 陈龙
// Copyright © 2019 陈龙. All rights reserved.
//
#include <iostream>
using namespace std;
int N,E;
int main(int argc, const char * argv[]) {
//N个顶点,E条边
cin>>N>>E;
int u,v,w;
int G[N][N];
//初始化无穷大
for (int i=0; i<N; i ) {//顶点i
for (int j=0; j<N; j ) {//目标顶点i
if(i==j)G[i][j]=0;
else G[i][j]=INT_MAX;
}
}
//构建有向图
for(int i=0;i<E;i ){
cin>>u>>v>>w;
G[u][v] = w;
}
//动态规划找中介
for (int k=0; k<N; k ) {//中介k
for (int i=0; i<N; i ) {//顶点i
for (int j=0; j<N; j ) {//目标顶点i
if((G[i][k]!=INT_MAX && G[k][j] !=INT_MAX ) && G[i][j]>G[i][k] G[k][j]){
G[i][j]=G[i][k] G[k][j];
}
}
}
}
//最短路径
cout<<"===";
for (int i=0; i<N; i ) {//顶点i
for (int j=0; j<N; j ) {//目标顶点i
cout<<i<<" "<<j<<" "<<G[i][j]<<endl;
}
}
return 0;
}
/*
eg:
3 3
0 1 1
0 2 2
1 2 -1
/*