1.定义概览
Floyd-Warshall算法(Floyd-Warshall algorithm)又称为插点法是解决任意两点间的最短路径的一种算法,可以正确处理有向图或负权的最短路径问题,同时也被用于计算有向图的传递闭包。Floyd-Warshall算法的时间复杂度为O(N3),空间复杂度为O(N2)。
2.算法描述:
1)算法思想原理:
Floyd算法是一个经典的动态规划算法。用通俗的语言来描述的话,首先我们的目标是寻找从点i到点j的最短路径。从动 态规划的角度看问题,我们需要为这个目标重新做一个诠释(这个诠释正是动态规划最富创造力的精华所在), 从任意节点i到任意节点j的最短路径不外乎2种可能,1是直接从i到j,2是从i经过若干个节点k到j。所以,我们假设
Dis(i,j)为节点u到节点v的最短路径的距离,对于每一个节点k,我们检查Dis(i,k) + Dis(k,j) < Dis(i,j)是否成立,如果成立,证明从i到k再到j的路径比i直接到j的路径
短,我们便设置Dis(i,j) = Dis(i,k) + Dis(k,j),这样一来,当我们遍历完所有节点k,Dis(i,j)中记录的便是i到j的最短路径的距离。
2).算法描述:
a.从任意一条单边路径开始。所有两点之间的距离是边的权,如果两点之间没有边相连,则权为无穷大。
b.对于每一对顶点 u 和 v,看看是否存在一个顶点 w 使得从 u 到 w 再到 v 比己知的路径更短。如果是更新它。
3).Floyd算法过程矩阵的计算----十字交叉法
补充其中用到的十字交叉法如下:
先来简单分析下,由于矩阵中对角线上的元素始终为0,因此以k为中间点时,从上一个矩阵到下一个矩阵变化时,矩阵的第k行,第k列和对角线上的元素是不发生改变的(对角线上都是0,因为一个顶点到自己的距离就是0,一直不变;而当k为中间点时,k到其他顶点(第k行)和其他顶点到k(第k列)的距离是不变的)。
因此每一步中我们只需要判断4*4-3*4+2=6个元素是否发生改变即可,也就是要判断既不在第k行第k列又不在对角线上的元素。具体计算步骤如下:以k为中间点(1)“三条线”:划去第k行,第k列,对角线(2)“十字交叉法”:对于任一个不在三条线上的元素x,均可与另外在k行k列上的3个元素构成一个2阶矩阵,x是否发生改变与2阶矩阵中不包含x的那条对角线上2个元素的和有关,若二者之和小于x,则用它们的和替换x,对应的Path矩阵中的与x相对应的位置用k来替代。。。
具体实例及代码如下所示:
/**
* @Title: Floyd.java
* @Package dynamicprogramming
* @Description: TODO
* @author peidong
* @date 2017-6-13 上午9:23:39
* @version V1.0
*/
package dynamicprogramming;
/**
* @ClassName: Floyd
* @Description: 弗洛伊德最短路径算法
* @date 2017-6-13 上午9:23:39
*
*/
public class Floyd {
public static void shorestFloyd(){
int MAX_VALUE = 65535;
int[][] edgesMatrix ={{0, 5, MAX_VALUE, 7}, {MAX_VALUE, 0, 4, 2}, {3, 3, 0, 2}, {MAX_VALUE, MAX_VALUE, 1, 0}};
int n = 4;//vertexSize; 结点个数
int[][] tc = new int[n][n]; //保存从i到j的最短路径值
int[][] p = new int[n][n]; //保存经过的中间结点
//初始化tc,p
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
p[i][j] = -1;
tc[i][j] = edgesMatrix[i][j]; //便矩阵
}
}
//进行Floyd算法,从0到n-1所有可能进行遍历
for(int x = 0; x < n; x++){ //x表示中间结点
for(int i = 0; i < n; i++){
for(int j = 0; j < n; j++){
if(tc[i][j] > tc[i][x] + tc[x][j]){
tc[i][j] = tc[i][x] + tc[x][j];
p[i][j] = x;
}
}
}
}
// 下面对获得的结果进行展示
System.out.println("最短路径状态转移矩阵为:");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(" " + tc[i][j]);
}
System.out.println();
}
System.out.println("对应的结点矩阵为:");
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.print(" " + p[i][j]);
}
System.out.println();
}
// System.out.println("+++++++++++++++++++++++++++++++++++");
/* for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
System.out.println("输出i=" + i + "到j=" + j + "最短路径:");
int k = p[i][j];
if (k == -1) {
System.out.println("没有最短路径");
} else {
System.out.print(" " + k);
while (k != j) {
k = p[k][j];
System.out.print(" " + k);
}
System.out.println(" "+k);
System.out.println();
}
}
} */
}
/**
* @Title: main
* @Description: 测试用例
* @param args
* @return void
* @throws
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
shorestFloyd();
}
}