美文网首页
最短路径 Floyd 算法

最短路径 Floyd 算法

作者: 一个追寻者的故事 | 来源:发表于2020-03-17 13:15 被阅读0次

    最短路径:对于带权的图来说,最短路径,是指两个顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点。

    核心思路:以所有的顶点为跳板,看看任意两个的顶点之间有无更短的路径,如果有则更新最短路径,最终得到的结果就是所有任意两个顶点之间的最短路径。

    应用:多个源点到其余各顶点的最短路径问题。

    应用实例:
    image.png

    无向图,如上图,求解各顶点之间最短路径。实现如下:

    /**
     * 求多源最短路径的算法。 时间复杂度O(n^3)
     */
    public class Floyd {
        public static final int I = 100;
        /**
         *           v0
         *        /  |   \
         *    (2)/  |(1)  \(5)
         *      /    |     \
         *    v1-----v2------v3
         *        (4)    (3)
         *
         */
        //邻接距阵 (代表顶点到顶点之间最短路径权值和的矩阵)
        public static int[][] d = new int[][]{
                {0, 2, 1, 5},
                {2, 0, 4, I},
                {1, 4, 0, 3},
                {5, I, 3, 0}
        };
        // p 代表 对应顶点最小路径的前驱矩阵
        public static int[][] p=new int[][]{
                {0,1,2,3},
                {0,1,2,3},
                {0,1,2,3},
                {0,1,2,3}
        };
        public static void floyd(){
            //第一层遍历: 分别以v0 v1 v2....v(d.length-1) 为跳板,计算所有路径权重的最小值
            for (int k = 0; k < d.length; k++) {
                //第二层遍历: 以确定的跳板为基础,遍历所有的行
                for (int i = 0; i < d.length; i++) {
                    //第三层遍历:以确定的跳板为基础,遍历所有的列
                    for (int j = 0; j < d.length; j++) {
                        //如果发现以跳板为基础的路径值更小,则更新d的值
                        if(d[i][j] > d[i][k] + d[k][j]){
                            d[i][j] = d[i][k] + d[k][j];
                            /**
                             *  记录一下路径:d[i][j]的值因跳板k而发生了变化:
                             *  (i, j) 的路径变成了   从(i,k),然后再从(k, j)。
                             *  所以前驱节点应该是 k, 但是假如(i, k)中间还有跳板,
                             *  即vi 到 vk 之间最短的路径 是经过了其他的节点的情况。
                             *  此时(i,j)的前驱节点,应该是(i,k)的前驱节点
                             */
                            p[i][j] = p[i][k];
                        }
                    }
                }
            }
        }
    
        /**
         * 打印路径
         */
        public static void printShortPath(){
            for (int i = 0; i < d.length; i++) {
                for (int j = 0; j < d.length; j++) {
                    System.out.print("v" + i + "->v" + j + "  weight: " + d[i][j]);
                    System.out.print("  path: " + "v" + i);
                    int k =p[i][j]; //取出 (i, j)的前驱节点:k
                    while (k != j){ //还有前驱节点
                        System.out.print("->" + "v" + k);
                        k = p[k][j];  //从前驱节点vk 开始,到vj 之间看还有没有前驱节点(跳板)
                    }
                    System.out.println("->" + "v" + k);
                }
            }
        }
    
    
        @Test
        public void test(){
            floyd();
            printShortPath();
        }
    }
    

    输出结果:

    v0->v0  weight: 0  path: v0->v0
    v0->v1  weight: 2  path: v0->v1
    v0->v2  weight: 1  path: v0->v2
    v0->v3  weight: 4  path: v0->v2->v3
    v1->v0  weight: 2  path: v1->v0
    v1->v1  weight: 0  path: v1->v1
    v1->v2  weight: 3  path: v1->v0->v2
    v1->v3  weight: 6  path: v1->v0->v2->v3
    v2->v0  weight: 1  path: v2->v0
    v2->v1  weight: 3  path: v2->v0->v1
    v2->v2  weight: 0  path: v2->v2
    v2->v3  weight: 3  path: v2->v3
    v3->v0  weight: 4  path: v3->v2->v0
    v3->v1  weight: 6  path: v3->v2->v0->v1
    v3->v2  weight: 3  path: v3->v2
    v3->v3  weight: 0  path: v3->v3
    

    相关文章

      网友评论

          本文标题:最短路径 Floyd 算法

          本文链接:https://www.haomeiwen.com/subject/ylctyhtx.html