最短路径

Posted xuweimdm

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短路径相关的知识,希望对你有一定的参考价值。

最短路径

问题

  • 对于如下的图来说,每一个“ ”代表一个节点,节点与节点之间是他们之间相应的边权,由于这个图类似于矩阵的形式,所以当给定坐标 (x1,y1)(x2,y2) 时,求这两个节点之间的最短路径。
  • 在下面这个图中,最原始的图应该是每条边代表转移概率,这里将概率乘以10取整后得到,也就是每个节点相连边的权值和为10.

5445|||||51215|||||3331|||||23254|||||1111|||||75635|||||3225

如何有效存储图?

  • 最通常存储图的方式主要有两种,一种是邻接矩阵,邻接矩阵比较直观易懂,但是通常来说非常消耗空间;另一种是邻接表。
  • 如果矩阵是 mn 阶的话,横向的边数为 m(n1) ,纵向的边数为 (m1)n ,因此总共的边数为 m(n1)+(m1)n=2mnmn ,所以在这里至少需要 O(2mnmn)=O(mn) 的存储空间,如果使用邻接矩阵的形式存储的话则需要 O(mnmn)=O(m2n2) 的存储空间,但是这里的每个节点最多与4个节点相邻,也就是最多与4条边相连,所以邻接矩阵的空间消耗是非常大的。

    • 这里使用两种方式存储这种图。
    • 用两个矩阵分别存储水平方向的边和垂直方向的边,分别命名为rows和cols,并且为了避免重复,在水平方向上的边只存储每个节点往右的边,在垂直方向上只存储每个节点往下的边。这样,最后一列和最后一行实际上是不需要存储的,但是为了方便起见,存储0也无妨。因此上述的图有

      rows = 
              5 4 4 5 0
              3 3 3 1 0
              1 1 1 1 0
              3 2 2 5 0     
      
      cols = 
              5 1 2 1 5
              2 3 2 5 4
              5 1 2 1 5
              0 0 0 0 0
      
    • 另外一种存储方式为:将图看做一个有向图,将向右和向下的边当做出边,针对每个节点只存该节点的出边,于是有如下存储方式:

      nodes = 
              5 5
              4 1
              4 2
              5 1
              0 5
              ...
              0 0
      

求解最短路径

  • 因为每条边权值都为正,所以用Dijkstra算法求解。基本思路是,从起始点出发,不断寻找当前能找到的离起始点最短路径的节点,然后以该节点作为中间节点,考察是否可以更新以该节点为中间节点的其他节点的距离。是一种层层递进的思路,直到到达所求的节点。基于这种思路,有以下解法:

Solution1

public int getMinPath1(int[][] rows, int[][] cols, int x1, int y1, int x2, int y2)//求(x1, y1)和(x2, y2)之间的最短路径
    int m = rows.length;
    if(m==0) return -1;
    int n = rows[0].length;
    if(n==0||x1>m||x2>m||x1<0||x2<0||y1>n||y2>n||y1<0||y2<0) return -1;//这些都是非法情况
    boolean[][] done = new boolean[m][n];//记录该节点是否已经找到最短路径了
    int[][] distance = new int[m][n];//记录从起始点到该节点的当前最短路径
    for(int i=0;i<m;i++) Arrays.fill(distance[i],Integer.MAX_VALUE);
    distance[x1][y1] = 0;//起始点的最短路径为0
    int x=0, y=0,min = Integer.MAX_VALUE;
    for(int k=0;k<m*n;k++,min = Integer.MAX_VALUE) //总共有m*n个节点,最坏情况下要循环m*n次
        for(int i=0;i<m;i++)       //找到还未考察过的节点中的最短路径
            for(int j=0;j<n;j++)
                if(!done[i][j]&&distance[i][j]<min)
                    x = i;
                    y = j;
                    min = distance[i][j];
                
            
        
        if(x == x2 && y == y2) return distance[x2][y2];//已经找到所求节点的最短路径了,直接退出
        done[x][y] = true;
        if(x > 0) distance[x-1][y] = Math.min(distance[x-1][y], distance[x][y] + cols[x-1][y]);//往上走
        if(x < m-1) distance[x+1][y] = Math.min(distance[x+1][y], distance[x][y] + cols[x][y]);//往下走
        if(y > 0) distance[x][y-1] = Math.min(distance[x][y-1], distance[x][y] + rows[x][y-1]);//往左走以上是关于最短路径的主要内容,如果未能解决你的问题,请参考以下文章

Java数据结构 最短路径解法Dijkstra算法

次短路径与次小生成树问题的简单解法——转自:BYVoid

最短路径问题 八年级数学上必考难点

最短路径之弗洛依德算法

Dijkstra 最短路径算法 秒懂详解

新人教版数学八上 轴对称之最短路径问题——基础知识基本方法思维提升有“套路”