弗洛伊德算法我已不再赘述,代码是
//Floyd-Warshall算法核心语句
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j] )
e[i][j]=e[i][k]+e[k][j];
需要注意的是,弗洛伊德算法的遍历的顺序是k,i,j,其中k是中点,必须放在最外层,如果k放在中间或者里面就会出错。感兴趣的读者请自行验证。
那么问题来了,为什么k必须放在最外面?数学上有个词叫完备性,是指在数学及其相关领域中,当一个对象不需要添加任何其他元素,那么称这个域是完备的,如实数集是完备的。这里引用完备性来表示弗洛伊德算法经过k,i,j这么一遍历,能把所有的情况都遍历到,没有遗漏,是为完备性。而如果k放在中间或者里面就会有遗漏,则不具备完备性。
以下是弗洛伊德算法的完备性的证明:
对任意一个路径图,如假设有1 2 3 4 5共5个点,不妨设他们之间的最短路为1->3->2->5->4,如图:
而原始图中1->2,3->5,5->4非最短路径,其中inf无穷大表示还未标识距离。
现在根据弗洛伊德算法,首先会遍历到2,路径3->2->5会变为3->5。
这样以2为中心节点的路径就会被“拉平”。这一轮遍历完后,就不必再考虑以2位中点的路径了,因为所有以2为中点的路径都已被“拉平”。
接下来再拉平3:
最后拉平5:
由此可得1->4的最短路径23。故对任意一条路径,通过该算法都可以得到其最短路径。
由此可得,通过依次拉平所有节点,最终可以得到任意一条路径的最短路。故而证明弗洛伊德算法具有完备性。
附:如果某个节点(如3节点)代表的路口正在维修,无法通行。这时如何计算不通过3节点的最短路?
很简单,k在遍历时不遍历3就行了。
//Floyd-Warshall算法核心语句
for(k=1;k<=n;k++)
if (k!=3)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j] )
e[i][j]=e[i][k]+e[k][j];
如果不经过3、5节点呢?k在遍历时不遍历3、5就行了。
//Floyd-Warshall算法核心语句
for(k=1;k<=n;k++)
if (k!=3 && k!=5)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(e[i][j]>e[i][k]+e[k][j] )
e[i][j]=e[i][k]+e[k][j];