问题的提法
-已知一个各边权值均大于0的带权有向图,对每一对顶点Vi≠Vj,求出Vi与Vj之间的最短路径值以及最短路径上的顶点。
Floyd算法核心
n阶方阵中元素的意义
-A^-1[i][j]:Vi到Vj的权值,无中间顶点
-A^0[i][j]:Vi到Vj的路径长度,路径的中间顶点为0
-A^1[i][j]:Vi到Vj的路径长度,路径的中间顶点可能为0或1
-……
-A^k[i][j]:Vi到Vj的路径长度,路径的中间顶点编号不大于k
-……
-A^n-1[i][j]:Vi到Vj的最短路径长度
Floyd算法精髓
-A^-1定义为邻接矩阵,则:
·A^0,……,A^n-1通过中转顶点逐一递推得到
-A^k矩阵中元素的更新:
·A^k[i][j] = min{ A^k-1[i][j],A^k-1[i][k] + A^k-1[k][j] }
-A矩阵的推导就是最短路径的推导
·矩阵的推导就是最短路径的推导
·A[i][j]为i到j的路径值,在推导过程中逐步减小
Floyd算法的实现:初始化
-本质:使用邻接矩阵初始化A^-1
for(int i = 0;i<vCount() ;i++)
{
for(int j = 0;j<vCount();j++)
{
dist[i][j] = getEdge(i,j);
}
}
Floyd算法的实现: A^0,...,A^n-1矩阵推导
-本质:使用中转顶点逐步推导最短路径
for(int k = 0;k<vCount();k++)
{
for(int i = 0;i<vCount();i++)
{
for(int j = 0;j<vCount() ;j++)
{
if(dist[i][k] + dist[k][j] < dist[i][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
}
}
}
}
定义辅助矩阵:
-int path[N][N]; //路径矩阵
·path[i][j]表示i到j的路径上所经过的第一个顶点
·初始化:path[i][j] = -1; or path[i][j] = j;
·修改:
if((dist[i][k] + dist [k][j]) < dist[i][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
path[i][j] = path[i][k];
}
SharedPointer<Array<int>> floyd(int x,int y ,const E& LIMIT)
{
LinkQueue<int> ret;
if((0 <= x) && (x <= vCount()) && (0 <= y) && (y < vCount()))
{
DynamicArray<DynamicArray<E>> dist(vCount());
DynamicArray<DynamicArray<int>> path(vCount());
for(int k = 0;k<vCount();k++)
{
dist[k].resize(vCount());
path[k].resize(vCount());
}
for(int i = 0;i<vCount();i++)
{
for(int j = 0;j<vCount();j++)
{
path[i][j] = -1;
dist[i][j] = isAdjacent(i,j)?getEdge(i,j) : LIMIT;
}
}
for(int k = 0;k < vCount(); k++)
{
for(int i = 0;i < vCount();i++)
{
for(int j =0;j<vCount();j++)
{
if((dist[i][k] + dist[k][j]) < dist[i][j])
{
path[i][j] = -1;
dist[i][j] = isAdjacent(i,j) ? (path[i][j] = j,getEdge(i,j)) : LIMIT;
}
}
}
}
for(int k = 0;k<vCount();k++)
{
for(int i = 0;i<vCount();i++)
{
for(int j = 0;j<vCount() ;j++)
{
if(dist[i][k] + dist[k][j] < dist[i][j])
{
dist[i][j] = dist[i][k] + dist[k][j];
path[i][j] = path[i][k];
}
}
}
}
while((x != -1) && ( x != y))
{
ret.add(x);
x = path[x][y];
}
if(x != -1)
{
ret.add(x);
}
}
else
{
//抛出异常
}
if(ret.length() < 2)
{
//抛出异常
}
return toArray(ret);
}
总结:
-Floyd算法通过递推逐步求得所有顶点间的最短路径
-Floyd算法的本质是通过中转顶点寻找更短的路径
-邻接矩阵是最短路径推导的其实矩阵
-路径矩阵记录了最短路径上的各个顶点