Floyd-Warshall 算法
设G的顶点为V={1,2,...,n},对于每个k考虑顶点的一个子集{1,2,...,k}。对于任意一对顶点i,j ∈ V,考察 从i到 j 且中间顶点皆属于集合{1,2,...,k}的所有路径,设p是其中的一条最小权值路径:
1)如果k不是路径p中的中间顶点,则p的所有中间顶点皆在集合{1,2,...,k-1}中。因此从顶点i到顶点j且满足所有中间顶点皆属于集合{1,2,...k-1}的一条最短路径,也同样从顶点i到顶点j且满足所有中间顶点皆属于集合{1,2,...,k}的一条最短路径。
2)如果k是路径p的中间顶点,那么p可以分解成两部分,如下图。p1是从i到k的一条最短路径,且其所有中间顶点属于集合{1,2,...,k}。因为顶点k不是路径p1上的一个中间顶点,所以p1是从i到k的一条最短路径,且其所有中间顶点均属于集合{1,2,...,k-1}.类似地,p2是从顶点k到顶点j的一条最短路径,且其所有中间顶点均属于集合{1,2,...,k-1}
令为从顶点i到顶点j,且满足所有中间顶点皆属于集合{1,2,...,k}的一条最短路径的权值,则有:
其中
伪代码如下:
运行时间:O(V^3)
完整代码:
#include<iostream>
#include<climits>
#include<iomanip>
using namespace std;
#define DG 0
#define UDG 1
#define NIL -1
typedef int vType;
typedef int wType;
typedef struct edge{
vType u; // the start of edge
vType v; // the end of edge
wType w; //the weight of edge
}edge;
typedef struct MGraph{
int vNum;
int eNum;
vType *V;
edge *E;
wType **W; //the weight matrix
int kind; // the type of the graph
}MGraph;
void Matrix_Print(wType **M,int n)
{
for(int i=0; i< n; i++)
{
for(int j=0; j<n; j++)
cout<<setw(12)<<M[i][j];
cout<<endl;
}
}
void Predecessor_Print(int **M,MGraph &G)
{
for(int i=0; i<G.vNum; i++)
{
for(int j=0; j<G.vNum; j++){
if(M[i][j]== NIL)
cout<<setw(12)<<"NIL";
else
cout<<setw(12)<<G.V[M[i][j]];
}
cout<<endl;
}
}
int Locate(MGraph &G,vType v)
{
for(int i=0; i<G.vNum; i++)
if(v == G.V[i])
return i;
return -1;
}
void Graph_Init(MGraph &G,vType V[],edge E[])
{
//init the vertices
G.V = new vType[G.vNum];
for(int i=0; i<G.vNum; i++)
G.V[i] = V[i];
//init the edge
G.E = new edge[G.eNum];
for(int i=0 ; i<G.eNum; i++){
G.E[i].u = E[i].u;
G.E[i].v = E[i].v;
G.E[i].w = E[i].w;
}
//init the weight matrix
G.W = new wType*[G.vNum];
for(int i=0 ;i<G.vNum; i++)
G.W[i] = new wType[G.vNum];
for(int i=0; i<G.vNum; i++)
for(int j=0; j<G.vNum; j++)
if(i == j)
G.W[i][j] = 0;
else
G.W[i][j] = INT_MAX;
for(int i=0; i<G.eNum; i++){
int u_i = Locate(G,E[i].u);
int v_i = Locate(G,E[i].v);
G.W[u_i][v_i] = E[i].w;
}
}
wType **Matrix_Copy(wType **M,int n)
{
wType **T = new wType*[n];
for(int i=0; i<n; i++)
T[i] = new wType[n];
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
T[i][j] = M[i][j];
return T;
}
void Floyd_WarShall(MGraph &G)
{
//when beginning ,D denote D[0]
wType **D = new wType*[G.vNum];
for(int i=0; i<G.vNum; i++)
D[i] = new wType[G.vNum];
D = Matrix_Copy(G.W,G.vNum);
// matrix tD store the (k-1)th result
wType **tD = new wType*[G.vNum];
for(int i=0; i<G.vNum; i++)
tD[i] = new wType[G.vNum];
//when beginning,Pie denote Pie[0]
int **Pie = new int*[G.vNum];
for(int i=0; i<G.vNum; i++)
Pie[i] = new int[G.vNum];
for(int i=0;i<G.vNum; i++)
for(int j=0; j<G.vNum; j++)
if(i==j || D[i][j]==INT_MAX)
Pie[i][j] = NIL;
else
Pie[i][j] = i;
//matrix tPie store the (k-1)th result
int **tPie = new int*[G.vNum];
for(int i=0; i<G.vNum; i++)
tPie[i] = new int[G.vNum];
// D denote the (k)th result
for(int k=0; k<G.vNum; k++ ){
tD = Matrix_Copy(D,G.vNum);
for(int i=0; i<G.vNum; i++)
for(int j=0; j<G.vNum; j++){
if(tD[i][k]>=INT_MAX || tD[k][j]>=INT_MAX || tD[i][k]+tD[k][j]>= INT_MAX)
D[i][j] = tD[i][j];
else
D[i][j] = min(tD[i][j],tD[i][k]+tD[k][j]);
}
cout<<"The "<<k+1<<"th roung weight matrix is:"<<endl;
Matrix_Print(D,G.vNum);
//Compute Matrix Pie
tPie = Matrix_Copy(Pie,G.vNum);
for(int i=0; i<G.vNum; i++)
for(int j=0; j<G.vNum; j++){
if(tD[i][k] == INT_MAX || tD[k][j] == INT_MAX || tD[i][k]+tD[k][j]>= INT_MAX)
{
Pie[i][j] = tPie[i][j];
continue ;
}
if(tD[i][j] <= tD[i][k]+tD[k][j])
Pie[i][j] = tPie[i][j];
else
Pie[i][j] = tPie[k][j];
}
cout<<"The "<<k+1<<"th round prececessor matrix is:"<<endl;
Predecessor_Print(Pie,G);
cout<<"----------------------------------------------"<<endl;
}
}
int main()
{
vType V[]={1,2,3,4,5};
edge E[]={{1,2,3},{1,3,8},{1,5 ,-4},
{2,4,1},{2,5,7},{3,2,4},
{4,1,2},{4,3,-5},{5,4,6}
};
MGraph G;
G.vNum = sizeof(V)/sizeof(vType);
G.eNum = sizeof(E)/sizeof(edge) ;
G.kind = DG;
Graph_Init(G,V,E);
Floyd_WarShall(G);
return 0;
}
运行结果: