动态规划实例(十五):最短路径Floyd

    本文参考http://blog.csdn.net/ochangwen/article/details/50730937

    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();
    }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章