自己把Dijkstra的板子整理了一下,也方便自己后续做题,在此做个记录。
Dijkstra基本上都会需要这些变量:
dist[]:记录各个节点到起始节点的最短权值
path[]:记录各个节点的上一个节点(用来联系该节点到起始节点的路径)
start:源点序号
end:结束顶点序号
weight[][]:存边的权重
visit[]:当前该顶点的最短路径是否已求出,即访没访问过
shortPath[]:存储每一次的最短路径的长度
感觉这些变量到最后还是需要根据题意灵活的舍取吧。
然后简单的解释一下Dijkstra算法的具体思路,也方便后续理解代码。
注意: 1.Dijkstra算法不适合带负权图。
2.计算单源最短路径问题。
Dijkstra算法的本质其实是贪心,说的通俗易懂点就是以起始点(源点)为中心向外层扩展(bfs),知道扩展到终点为止。
具体的算法过程如下:
声明一个数组dist[]来保存源点到各个顶点的最短距离,声明一个保存已经找到了最短路径的顶点的集合T。然后初始化的时候,源点u的路径权重被赋值为0,即dist[u] = 0,如果这个顶点u存在能直接到达的边(u,v),就把dist[v]设为weight[u][v],(其中weight[i][j]表示(i,j)这条边的权重),同时把所有其他(u不能直接到达的)顶点的路径长度设为无穷大。初始时,集合T只有顶点s。
然后,从dist[]中选择最小值,这个最小值就是源点u到该值对应的顶点的最短路径,并且把该点加入到T中,此时我们就完成了第一个顶点的添加,除去源点,我们要加n-1个顶点。
接着,我们需要看看新加入的顶点是否可以到达其他顶点,并且还要看通过该顶点到达其他点的路径长度是否比源点直接到达短,如果短的话,我们就替换这些顶点在dist中的值,也叫松弛操作。之后重复这一步就可以,直到T中包含了图的所有顶点。
但是正常做题的时候好像并不会单独创建一个集合去存顶点,一般都是用boolean visit[]数组,标记一下就行吧。
下面是我找到的Dijkstra板子:
public class 迪杰斯特拉 {static int M = 1000; // 表示两个节点之间没有路public static void main(String[] args) {int[][] weight = {{0, M, 10, M, 30, 100},{M, 0, 5, M, M, M},{M, M, 0, 50, M, M},{M, M, M, 0, M, 10},{M, M, M, 20, 0, 60},{M, M, M, M, M, 0}};int start = 0; // 表示从源点开始// 存储每一次的最短路径的长度int[] shortPath = Dijkstra(weight,start);for(int i = 0;i < shortPath.length;i ++) {// 说明start点到i点没有最短路if (shortPath[i] == M) {continue;}System.out.println("从" + start+ "出发到" + i + "最短距离是:" + shortPath[i]);}}public static int[] Dijkstra(int [][]weight, 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] = start + "->" + i;}boolean[] visit = new boolean[n]; // 标记当前该顶点的最短路径是否已求出,1表示已求出// 进行初始化shortPath[start] = 0;visit[start] = true;for(int cnt = 1;cnt < n; cnt ++) { // 加入其余n-1个节点int k = 0; // 选出一个距离初始顶点最近的未被标记的点int min = Integer.MAX_VALUE;for(int i = 0;i < n;i ++) {// 表示该点未确定最短路径,并且start到该点有直接连接if (!visit[i] && weight[start][i] < min) {min = weight[start][i];k = i;}}// 把刚刚新选出的顶点标记为以求出最短路径,并且路径长度为minvisit[k] = true;shortPath[k] = min;// 这个时候k作为中转节点,来进一步判断start到未访问的其他顶点的距离for(int i = 0;i < n;i ++) {// 表示由start到顶点i有一条路是经过顶点k的,并且要比start直接到达顶点i的距离要短,然后就更新,也叫松弛操作if (!visit[i] && 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 ++) {if (shortPath[i] == M) {continue;}System.out.println("从" + start + "出发到" + i + "的最短路径:" + path[i]);}return shortPath;}
}