一、问题概述
定义:在给定赋权图G及图G中两点u、v,求u到v具有最小权重的路的问题叫做最短路问题。
解决问题的算法主要有:
- Dijkstra算法
-
Bellman-Ford 算法
- Floyd-Warshall算法
本文仅粗略的描述一下Dijkstra算法。
二、Dijkstra算法
- 算法特点
Dijkstra算法使用了广度优先搜索解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路径树。
- 算法思路
Dijkstra
算法采用的是一种
贪心的策略
,声明一个数组
dis
来保存源点到各个顶点的最短距离和一个保存已经找到了最短路径的顶点的集合:T
,初始时,原点
s
的路径权重被赋为
0 (dis[s] = 0
)。若对于顶点 s
存在能直接到达的边(
s,m
),则把
dis[m]
设为
w
(
s, m
)
,
同时把所有其他(
s
不能直接到达的)顶点的路径长度设为无穷大。
初始时,集合T
只有顶点
s。
然后,从dis
数组选择最小值,则该值就是源点
s
到该值对应的顶点的最短路径,并且把该点加入到T中,
OK
,此时完成一个顶点,然后,我们需要看看新加入的顶点是否可以到达其他顶点并且看看通过该顶点到达其他点的路径长度是否比源点直接到达短,如果是,那么就替换这些顶点在dis
中的值。
然后,又从
dis
中找出最小值,
重复上述动作
,直到
T
中包含了图的所有顶点
。
三、代码实现
/**
* Dijkstra 算法
*/
public static int[] dijkstra(int[][] weight, int start) {
// 接受一个有向图的权重矩阵,和一个起点编号start(从0编号,顶点存在数组中)
// 返回一个int[] 数组,表示从start到它的最短路径长度
int n = weight.length; // 顶点个数
int[] shortPath = new int[n]; // 保存start到其他各点的最短路径
String[] path = new String[n]; // 保存start到其他各点最短路径的字符串表示
for (int i = 0; i < n; i++)
path[i] = new String(start + "-->" + i);
int[] visited = new int[n]; // 标记当前该顶点的最短路径是否已经求出,1表示已求出
// 初始化,第一个顶点已经求出
shortPath[start] = 0;
visited[start] = 1;
for (int count = 1; count < n; count++) { // 要加入n-1个顶点
int k = -1; // 选出一个距离初始顶点start最近的未标记顶点
int dmin = Integer.MAX_VALUE;
for (int i = 0; i < n; i++) {
if (visited[i] == 0 && weight[start][i] < dmin) {
dmin = weight[start][i];
k = i;
}
}
// 将新选出的顶点标记为已求出最短路径,且到start的最短路径就是dmin
shortPath[k] = dmin;
visited[k] = 1;
// 以k为中间点,修正从start到未访问各点的距离
for (int i = 0; i < n; i++) {
//如果 '起始点到当前点距离' + '当前点到某点距离' < '起始点到某点距离', 则更新
if (visited[i] == 0 && weight[start][k] + weight[k][i] < weight[start][i]) {
weight[start][i] = weight[start][k] + weight[k][i];
path[i] = path[k] + "-->" + i;
}
}
}
for (int i = 0; i < n; i++) {
System.out.println("从" + start + "出发到" + i + "的最短路径为:" + path[i]);
}
return shortPath;
}