Floyd算法
有向图中任意两节点(s,e)之间的最短距离,无非就从两种情况中产生:
1. 通过有向边{s,e}由s直达e
2. 由s出发,经过若干有向边和中转节点,最终到达e
仿照Bellman-Ford算法部分,得到以下图表:
解释一下转移关系:
对于每个节点k,最短路径可以经过k,也可以不经过k。此时节点k视作未候选,候选中转节点就是1∼k−1,对应d(k−1,i,j)的状态,此时一种情况是从i出发,先走到k再走到j,就是d(k−1,i,k)+d(k−1,k,j),另一种情况直接从i走到j,就是d(k−1,i,j),两者取最小值。
由于对任意k0,k=k0状态仅与k=k0−1状态有关,且两状态之间不会互相覆盖,故可以直接在原地修改
C++ 代码
对前置知识中MGraph类稍作修改
class MGraph {
private:
int** mat;
int numVex, numArc;
const int INF = 1e9 + 7;//添加无穷大量
public:
//构造函数稍作修改,预处理距离表
MGraph(int n, int m) {
numVex = n;
numArc = m;
mat = new int[numVex + 1];
for (int i = 0; i <= numVex; i++) {
mat[i] = new int[numVex + 1];
//把邻接矩阵mat直接当作距离表
fill(mat[i], mat[i] + numVex, INF);
mat[i][i] = 0;
}
size_t s, e;
int v;
while (m--) {
cin >> s >> e >> v;
//不保证不存在重边和自环
mat[s][e] = min(mat[s][e], v);
}
//按顺序枚举状态位k,i,j
for (int k = 1; k <= numVex; k++) {
for (int i = 1; i <= numVex; i++) {
for (int j = 1; j <= numVex; j++) {
mat[i][j] = min(mat[i][j], mat[i][k] + mat[k][j]);
}
}
}
}
//查询从s到e的最短距离
int getShortestPath(int s, int e) {
int& dist = mat[s][e];
//Floyd算法也可以处理负权边,同样不支持负权回路
return ((dist >= INF / 2) ? INT_MIN : dist);
}
//析构函数保持不变,此处暂时省略
}