最短路径
Posted xuweimdm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最短路径相关的知识,希望对你有一定的参考价值。
最短路径
问题
- 对于如下的图来说,每一个“ ∙ ”代表一个节点,节点与节点之间是他们之间相应的边权,由于这个图类似于矩阵的形式,所以当给定坐标 (x1,y1)和(x2,y2) 时,求这两个节点之间的最短路径。
- 在下面这个图中,最原始的图应该是每条边代表转移概率,这里将概率乘以10取整后得到,也就是每个节点相连边的权值和为10.
∙−5−∙−4−∙−4−∙−5−∙|||||51215|||||∙−3−∙−3−∙−3−∙−1−∙|||||23254|||||∙−1−∙−1−∙−1−∙−1−∙|||||75635|||||∙−3−∙−2−∙−2−∙−5−∙
如何有效存储图?
- 最通常存储图的方式主要有两种,一种是邻接矩阵,邻接矩阵比较直观易懂,但是通常来说非常消耗空间;另一种是邻接表。
如果矩阵是 m∗n 阶的话,横向的边数为 m∗(n−1) ,纵向的边数为 (m−1)∗n ,因此总共的边数为 m∗(n−1)+(m−1)∗n=2mn−m−n ,所以在这里至少需要 O(2mn−m−n)=O(mn) 的存储空间,如果使用邻接矩阵的形式存储的话则需要 O(mn∗mn)=O(m2∗n2) 的存储空间,但是这里的每个节点最多与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]);//往左走以上是关于最短路径的主要内容,如果未能解决你的问题,请参考以下文章