Wiki上有该算法的原理如下:
设为从到的只以集合中的节点为中间节点的最短路径的长度。
- 若最短路径经过点k,则;
- 若最短路径不经过点k,则。
因此,。
顶点对之间的最短路径是指:对于给定的有向网G=(V,E),要对G中任意一对顶点有序对V、W(V≠W),找出V到W的最短距离和W到V的最短距离。
解决此问题的一个有效方法是:轮流以每一个顶点为源点,重复执行迪杰斯特拉算法n次,即可求得每一对顶点之间的最短路径,总的时间复杂度为O(n3)。
弗洛伊德(Floyd)提出了另外一个求图中任意两顶点之间最短路径的算法,虽然其时间复杂度也是 O(n3),但其算法的形式更简单,易于理解和编程。
算法基本思想
弗洛伊德算法仍然使用图的邻接矩阵arcs[n+1][n+1]来存储带权有向图。算法的基本思想是:设置一个n x n的矩阵A(k),其中除对角线的元素都等于0外,其它元素a(k)[i][j]表示顶点i到顶点j的路径长度,K表示运算步骤。开始时,以任意两个顶点之间的有向边的权值作为路径长度,没有有向边时,路径长度为∞,当K=0时, A (0)[i][j]=arcs[i][j],以后逐步尝试在原路径中加入其它顶点作为中间顶点,如果增加中间顶点后,得到的路径比原来的路径长度减少了,则以此新路径代替原路径,修改矩阵元素。具体做法为:
第一步,让所有边上加入中间顶点1,取A[i][j]与A[i][1]+A[1][j]中较小的值作A[i][j]的值,完成后得到A(1),
第二步,让所有边上加入中间顶点2,取A[i][j]与A[i][2]+A[2][j]中较小的值,完成后得到A(2)…,如此进行下去,当第n步完成后,得到A(n),A(n)即为我们所求结果,A(n)[i][j]表示顶点i到顶点j的最短距离。
因此,弗洛伊德算法可以描述为:
A(0)[i][j]=arcs[i][j]; //arcs为图的邻接矩阵
A(k)[i][j]=min{A(k-1) [i][j],A(k-1) [i][k]+A(k-1) [k][j]}
其中 k=1,2,…,n
定义一个n阶方阵序列:
D(-1), D(0), …, D(n-1).
其中 D(-1) [i][j] = G.arcs[i][j];
D(k) [i][j] = min { D(k-1)[i][j],D(k-1)[i][k] + D(k-1)[k][j] }, k = 0,1,…, n-1
D(0) [i][j]是从顶点vi 到vj , 中间顶点是v0的最短路径的长度,
D(k) [i][j]是从顶点vi 到vj , 中间顶点的序号不大于k的最短路径长度,
D(n-1)[i][j]是从顶点vi 到vj 的最短路径长度。
代码如下:
- #include <iostream>
- #define GRAPHSIZE 12
- #define MAX_INT 0x7FFFFFFF
- #define NO_PAHT -1
- using namespace std;
- class Graph
- {
- public:
- long map[GRAPHSIZE][GRAPHSIZE];
- void floydWarshall();
- void getData();
- void putResult();
- private:
- int vertexNum;
- int path[GRAPHSIZE][GRAPHSIZE]; //path[i][j] means the last but one vertex in the shortest path from i to j.
- long distance[GRAPHSIZE][GRAPHSIZE][GRAPHSIZE]; //distance[i][j][k] means the cost of the shortest path, which has no vertex more than k between.
- void initialize();
- void putPath(int source, int destination);
- };
- void Graph::getData()
- {
- cout << "Please input the vertex number, no more than " << GRAPHSIZE - 1 << ": ";
- cin >> vertexNum;
- cout << "Please input edge number: ";
- int edgenum;
- int source, destination,cost;
- cin >> edgenum;
- while (edgenum--)
- {
- cin >> source >> destination >> cost;
- map[source][destination] = cost;
- }
- }
- void Graph::putPath(int source, int destination)
- {
- if (source == destination)
- {
- cout << source;
- }
- else if (NO_PAHT == path[source][destination])
- {
- cout << source << " " << destination << " ";
- }
- else
- {
- putPath(source, path[source][destination]);
- cout << destination << " ";
- }
- }
- void Graph::putResult()
- {
- int shortest;
- for (int i = 0; i < vertexNum; i++)
- {
- for (int j = 0; j < vertexNum; j++)
- {
- cout << "From vertex_" << i << " to vertex_" << j << " is: ";
- shortest = distance[i][j][0];
- for (int k = 1; k <= vertexNum; k++)
- {
- if (shortest > distance[i][j][k])
- {
- shortest = distance[i][j][k];
- }
- }
- if (shortest == MAX_INT)
- {
- cout << "+∞" << endl;
- }
- else
- {
- cout << shortest << " Path: ";
- putPath(i, j);
- cout << endl;
- }
- }
- }
- }
- void Graph::initialize()
- {
- for (int i = 0; i < GRAPHSIZE; i++)
- {
- for (int j = 0; j < GRAPHSIZE; j++)
- {
- for (int k = 0; k < GRAPHSIZE; k++)
- {
- distance[i][j][k] = MAX_INT;
- }
- map[i][j] = MAX_INT;
- if (i == j)
- {
- map[i][j] = 0;
- }
- path[i][j] = NO_PAHT;
- }
- }
- getData();
- for (int i = 0; i < GRAPHSIZE; i++)
- {
- for (int j = 0; j < GRAPHSIZE; j++)
- {
- distance[i][j][0] = map[i][j];
- }
- }
- }
- void Graph::floydWarshall()
- {
- initialize();
- int k, i, j;
- for (k = 1; k < vertexNum; k++)
- {
- for (i = 0; i < vertexNum; i++)
- {
- for (j = 0; j < vertexNum; j++)
- {
- distance[i][j][k] = distance[i][j][k - 1];
- if (distance[i][k][k - 1] != MAX_INT && distance[k][j][k - 1] != MAX_INT && distance[i][j][k] > distance[i][k][k - 1] + distance[k][j][k - 1])
- {
- distance[i][j][k] = distance[i][k][k - 1] + distance[k][j][k - 1];
- path[i][j] = k;
- }
- }
- }
- }
- }
- int main()
- {
- Graph test;
- test.floydWarshall();
- test.putResult();
- return 0;
- }
其实,也说到了,可以进行优化,空间上的优化。既是在原来的空间上进行迭代,将空间优化为二维,如下:
代码如下:
- #include <iostream>
- #define GRAPHSIZE 12
- #define MAX_INT 0x7FFFFFFF
- #define NO_PAHT -1
- using namespace std;
- class Graph
- {
- public:
- long map[GRAPHSIZE][GRAPHSIZE];
- void floydWarshall();
- void getData();
- void putResult();
- private:
- int vertexNum;
- int path[GRAPHSIZE][GRAPHSIZE]; //path[i][j] means the last but one vertex in the shortest path from i to j.
- long distance[GRAPHSIZE][GRAPHSIZE]; //distance[i][j] means the cost of the shortest path from i to j.
- void initialize();
- void putPath(int source, int destination);
- };
- void Graph::getData()
- {
- cout << "Please input the vertex number, no more than " << GRAPHSIZE - 1 << ": ";
- cin >> vertexNum;
- cout << "Please input edge number: ";
- int edgenum;
- int source, destination,cost;
- cin >> edgenum;
- while (edgenum--)
- {
- cin >> source >> destination >> cost;
- map[source][destination] = cost;
- }
- }
- void Graph::putPath(int source, int destination)
- {
- if (source == destination)
- {
- cout << source;
- }
- else if (NO_PAHT == path[source][destination])
- {
- cout << source << " " << destination << " ";
- }
- else
- {
- putPath(source, path[source][destination]);
- cout << destination << " ";
- }
- }
- void Graph::putResult()
- {
- int shortest;
- for (int i = 0; i < vertexNum; i++)
- {
- for (int j = 0; j < vertexNum; j++)
- {
- cout << "From vertex_" << i << " to vertex_" << j << " is: ";
- shortest = distance[i][j];
- if (shortest == MAX_INT)
- {
- cout << "+∞" << endl;
- }
- else
- {
- cout << shortest << " Path: ";
- putPath(i, j);
- cout << endl;
- }
- }
- }
- }
- void Graph::initialize()
- {
- for (int i = 0; i < GRAPHSIZE; i++)
- {
- for (int j = 0; j < GRAPHSIZE; j++)
- {
- distance[i][j] = MAX_INT;
- map[i][j] = MAX_INT;
- if (i == j)
- {
- map[i][j] = 0;
- }
- path[i][j] = NO_PAHT;
- }
- }
- getData();
- for (int i = 0; i < GRAPHSIZE; i++)
- {
- for (int j = 0; j < GRAPHSIZE; j++)
- {
- distance[i][j] = map[i][j];
- }
- }
- }
- void Graph::floydWarshall()
- {
- initialize();
- int k, i, j;
- for (k = 1; k < vertexNum; k++)
- {
- for (i = 0; i < vertexNum; i++)
- {
- for (j = 0; j < vertexNum; j++)
- {
- if (distance[i][k] != MAX_INT && distance[k][j] != MAX_INT && distance[i][j] > distance[i][k] + distance[k][j])
- {
- distance[i][j] = distance[i][k] + distance[k][j];
- path[i][j] = k;
- }
- }
- }
- }
- }
- int main()
- {
- Graph test;
- test.floydWarshall();
- test.putResult();
- return 0;
- }
- 转载于:http://blog.csdn.net/betabin/article/details/7385663