floydwarshall algorithm(弗洛伊德算法):对每一个顶点,都要尝试它作为任一对顶点的中转顶点的可能性。基于此,形成一个基础数据库。在这个基础数据库的基础上,追溯出任意两点的最短路径。
对几个疑问的解释:
1.简单的循环条件,如for (k=0;k<n;k++)
for(i=0;i<n;i++)
for(j=0;j<n;j++)
是否会造成顶点的覆叠?比如k=1;i=0;j=1;
解释:覆叠是会的。但是如例中情况,我们认为k=1,是i=0和j=1的中转顶点。因而,和总体的原则是统一的,不会影响结果。
2.为什么会要先有一个全面的基础数据库,不能直接得出任意两点的最短路径吗?
答:任意两点的路径,它们之间可能有中转顶点,也可能没有。但是它们的中转顶点之间,可能还有其他中转顶点;其他中转顶点之间,可能还有其他其他中转顶点......因此,虽然只是两个顶点的最短路径问题,但是关乎全局的顶点对之间的中转信息。因此,需要一个全面的包含所有的中转顶点的基础数据库。
下面是floydwarshall algorithm(弗洛伊德算法)的c语言代码。在最后追溯两点之间的中间顶点的时候,我没有用栈,而是用的递归函数。
#include "stdio.h"
#define NUM 4
#define CN ( (NUM-1)+1 )*NUM/2
void short_path(int E[NUM][NUM],int u,int v);
void trace_back(int path[][NUM],int u,int v);
main()
{
int n;
n = NUM;
int E[n][n];
int i,j;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if (i==j)
E[i][j]=0;
int ni[CN]={3,10,18,6,15,2};//necessary information;
int k;
k=0;
for (i=0;i<n;i++)
for(j=i+1;j<n;j++)
E[i][j] = ni[k++];
for(j=0;j<n;j++)
for(i=j+1;i<n;i++)
E[i][j] = E[j][i];
for (i=0;i<n;i++)
for(j=0;j<n;j++)
if (j == n-1)
printf("%-2d\n",E[i][j]);
else
printf("%-2d ", E[i][j]);
short_path(E,0,3);
}
void short_path(int E[NUM][NUM],int u,int v)
{
int n;
n=NUM;
int dist[NUM][NUM];
int path[NUM][NUM];
int i,j,k;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
dist[i][j]=E[i][j];
for(i=0;i<n;i++)
for(j=0;j<n;j++)
path[i][j]=-1;
for(k=0;k<n;k++)
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(dist[i][k]+dist[k][j]< dist[i][j])
{dist[i][j] = dist[i][k]+dist[k][j];
path[i][j] = k;}
printf("%d ",u);
trace_back(path,u,v);
}
void trace_back(int path[][NUM],int u,int v)
{
if(path[u][v] != -1)
trace_back(path,u,path[u][v]);
printf("%d ",v);
}