单源最短路径算法——Dijkstra

一、相关概念

单源最短路径

图中某一顶点到其他各顶点的最短路径,可通过经典的Dijkstra算法求解,此算法是基于贪心算法的策略。
注:如果边上带负权值,Dijkstra并不适用。适用于权值非负的有向图或无向图

图中每一对顶点间的最短路径

可通过Floyd-Warshall算法来求解,此算法是基于动态规划的思想

二、题目

题目

单源最短路径算法——Dijkstra_第1张图片
1.png

单源最短路径算法——Dijkstra_第2张图片
2.png

思路

这个算法是基于贪心策略的(手动求解思路,参考下图)

单源最短路径算法——Dijkstra_第3张图片

单源最短路径算法——Dijkstra_第4张图片

代码

import java.util.Scanner;
import java.util.Stack;

/**
 * 
 * 

* Description: *

* * @author 杨丽金 * @date 2018-8-24 * @version 1.0 */ public class 最短路径算法 { public static void main(String[] args) { new 最短路径算法().exe(); } /*class Node { // 节点编号 int num; }*/ // 用邻接矩阵存储图 class MGraph { // 节点数 int n; // 边数 int e; // 节点(节点编号从0开始) // Node[] nodes; // 边 int[][] edges; public MGraph(int n, int e) { this.n = n; this.e = e; // nodes = new Node[n]; edges = new int[n][n]; // 各个边初始化为一个特别大的值 for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (i == j) { edges[i][j] = 0; } else { edges[i][j] = Integer.MAX_VALUE; } } } } @Override public String toString() { return "MGraph [n=" + n + ", e=" + e + ", nodes="; } } private void exe() { Scanner scan = new Scanner(System.in); // 节点数 int N = scan.nextInt(); // 边数 int M = scan.nextInt(); MGraph g = new MGraph(N, M); // 读入各个边 for (int i = 0; i < M; i++) { int A = scan.nextInt(); int B = scan.nextInt(); int X = scan.nextInt(); g.edges[A][B] = X; g.edges[B][A] = X; } int S = scan.nextInt(); int T = scan.nextInt(); // 输出 System.out.println(g); for (int i = 0; i < g.n; i++) { for (int j = 0; j < g.n; j++) { System.out.print(g.edges[i][j] + "\t"); } System.out.println(); } // 得到最短路径长度{有最短路径:返回长度;无:-1} int r = getMinimumRoad(g, S, T); System.out.println(); System.out.println(r); // System.out.println("最短路径上的节点"); printPath(S,T,path); } /** * 打印从节点S到节点T的最短路径上经过的节点 * @param t * @param set2 */ private void printPath(int S,int T, int[] myPath) { Stack stack=new Stack<>(); int i=T; while(myPath[i]!=-1){ stack.push(i); i=myPath[i]; } stack.push(S); while(!stack.isEmpty()){ // 出栈 int temp=stack.pop(); System.out.print(temp+"\t"); } System.out.println(); } /* * Dijkstra需要3个辅助数组 1,set[] 2,dist[] 3,path[] */ // 标志节点是否已找到最短路径 int[] set; // 标志从起始节点S到节点i的最短路径长度 int[] dist; // 起始节点S到节点i的最短路径上i的前一节点 int[] path; /** * dijkstra算法:基于贪心策略 每次都从dist数组中找出最小的值并入到集合中,然后再更改path、dist集合 * * @param g * @param S * @param T * @return */ private int getMinimumRoad(MGraph g, int S, int T) { set = new int[g.n]; // 标志从起始节点S到节点i的最短路径长度 dist = new int[g.n]; // 起始节点S到节点i的最短路径上i的前一节点 path = new int[g.n]; /* * 初始化这些数组 set[] :初始化时 S节点标志位1,其余的标志位0 dist[] * :用图的edges[][]数组中的edges[S][i]代替 * path[]:S到i有路径则path[i]=S;若无路径,则path[i]=-1 */ // set[] :初始化时 S节点标志位1,其余的标志位0 set[S] = 1; // dist[] :用图的edges[][]数组中的edges[S][i]代替 for (int i = 0; i < g.n; i++) { dist[i] = g.edges[S][i]; } // path[]:S到i有路径则path[i]=S;若无路径,则path[i]=-1 for (int i = 0; i < g.n; i++) { if (g.edges[S][i] == Integer.MAX_VALUE) { // 无路径 path[i] = -1; } else { path[i] = S; } } path[S] = -1; System.out.print("set[]:"); for (int i = 0; i < g.n; i++) { System.out.print(set[i] + "\t"); } System.out.println(); System.out.print("dist[]:"); for (int i = 0; i < g.n; i++) { System.out.print(dist[i] + "\t"); } System.out.println(); System.out.print("path[]:"); for (int i = 0; i < g.n; i++) { System.out.print(path[i] + "\t"); } System.out.println(); // 更新set[]、dist[]、path[] dijkstra(g, set, path, dist); System.out.print("set[]:"); for (int i = 0; i < g.n; i++) { System.out.print(set[i] + "\t"); } System.out.println(); System.out.print("dist[]:"); for (int i = 0; i < g.n; i++) { System.out.print(dist[i] + "\t"); } System.out.println(); System.out.print("path[]:"); for (int i = 0; i < g.n; i++) { System.out.print(path[i] + "\t"); } return dist[T]==Integer.MAX_VALUE? -1:dist[T]; } private void dijkstra(MGraph g, int[] set, int[] path, int[] dist) { // 求最短路径 for (int i = 0; i < g.n - 2; i++) { // 进行n-2轮循环 // 找出dist[] 中最小的k(太贪心) int k = -1; int min = Integer.MAX_VALUE; for (int j = 0; j < g.n; j++) { if (set[j] == 0) { // 还未并入集合 if (dist[j] < min) { min = dist[j]; k = j; } } } // 将上述k节点并入集合set中,更新path[]、dist[] set[k] = 1; for (int m = 0; m < g.n; m++) { if (set[m] == 0) { // 还未合并入集合 // 更新dist// 更新path if(g.edges[k][m]==Integer.MAX_VALUE){ // k到m无路径,则不用再往下判断了 continue; } int temp = dist[k] + g.edges[k][m]; if (temp < dist[m]) { dist[m] = temp; path[m] = k; } } } } } }

参考文献

最基础的Dijkstra的应用
王道论坛数据结构最短路径

你可能感兴趣的:(单源最短路径算法——Dijkstra)