最短路算法dijkstra算法

dijkstra最短路算法,使用贪心策略,解决有权图单源最短路问题。

BFS最短路算法

从源点s开始将顶点依次加入到已确定了最短路径的顶点集合S中,由于图是无权图(每条边权值也可以看做1)。
具体来讲,每次将距离源点s距离为k(k=0,1,2,...)的顶点加入已经确定最短路的顶点S中, 下次再将未加入S中,和源点s距离为k的顶点直接相连的顶点(也就是距离源点距离为k+1的顶点)加入到集合S中。重复上述过程,直到所有顶点都加入到S中,就得到了从源点s到所有顶点的最短距离。

dijkstra 算法

类似BFS算法,也就是BFS算法的推广,从源点s开始将顶点依次加入到已确定了最短路径的顶点集合S中。
这时的图是带权值(朴素做法,遍历所有未加入S中顶点选择距离最小的顶点(时间复杂度为O(V)))。因此我们不能像BFS那样,根据距离源点为k的顶点扩展其直接相连但未加入集合S的顶点作为距离源点距离k+1的点加入集合。而是从未加入集合S的顶点中一条挑选距离源点距离最近的点v加入集合S。为什么可以这样做呢,这就是贪心策略,因为我们从未加入顶点中再也找不到一个顶点x,使得点v通过点x中转比点v不通过未加入点中转距离源点s更近,即(d_{sx}+d_{xv})一定会大于(d_{sv}),因此,我们可以选择这样一个顶点v,直接加入集合S中。但加入S中,点v可能影响到集合S中点距离源点的距离(也就是通过点v进行中转,可能得到更短的距离), 如果v可能影响的点y到源点的距离,那么v一定在y到源点的最短路径上,并且y和v一定存在边直接相连(y是v的邻接点)。因为,不可能再找到S中一个顶点m,使得v到m,m再到y的距离更近((d_{sv}+d_{vm}+d_{my}) > (d_{sv}++d_{vy})),这是因为v是后加入的(d_{sv}) > (d_{sm}),如果存在m,显然不走v距离更短((d_{sm}) < (d_{sv}+d_{vm})。总结一下,就是每次加入一个点v后,需要对已经加入S中,并且是v的邻接点到源点的距离进行更新。朴素做法,对所有点都进行更新(时间复杂度为:O(V))。
每次加入一个顶点时间复杂度为)O(V), 每次加入需要O(V)时间复杂度挑选距离源点最小顶点和更新已近加入的点。操作过程,设计到每个顶点的邻接点(对每条边的访问)因此,时间复杂度为(O(V*V+E))
挑选距离源点最小顶点可以使用堆优化,时间复杂度O(logV),更新v的已经加入S的邻接点到源点距离时间复杂度也是O(logV),因此,综合时间复杂度为O(VlogV+E)。
因此,稠密图选择朴素版,稀疏图选择堆优化版比较好。

import java.util.*;
public class Main {
   
    static void dijkstra(int[][] g, int[] dist, int n, int x) {
        boolean[] st = new boolean[n+1];
        dist[x] = 0;
        for(int i=1; i <= n; i++) {
            int t = -1;
            for(int j=1; j <= n; j++) 
                if(st[j] == false && (t == -1 || dist[t] > dist[j]))
                    t = j;
            st[t] = true;
            for(int j=1; j <= n; j++) {
                dist[j] = Math.min(dist[j], dist[t] + g[t][j]);
            }
        }
        //System.out.println(Arrays.toString(dist));
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(), m = sc.nextInt();
        int[][] g = new int[n+1][n+1];
        int[] dist = new int[n+1];
        for(int i=0; i <= n; i++) 
            for(int j=0; j <= n; j++) 
                if(i == j) g[i][i] = 0;
                else g[i][j] = Integer.MAX_VALUE >> 1;
        for(int i=0; i < m; i++){
            int x = sc.nextInt(), y = sc.nextInt(), z = sc.nextInt();
            g[x][y] = Math.min(g[x][y], z);
        }
        //System.out.println(Arrays.deepToString(g));
        Arrays.fill(dist, Integer.MAX_VALUE);
        dijkstra(g, dist, n, 1);
        if(Integer.MAX_VALUE >> 1 == dist[n])
            System.out.println(-1);
        else
            System.out.println(dist[n]);
    }
}

不存在边初始化为-1的版本

import java.util.*;
public class Main {
   
    static void dijkstra(int[][] g, int[] dist, int n, int x) {
        boolean[] st = new boolean[n+1];
        dist[x] = 0;
        for(int i=1; i <= n; i++) {
            int t = -1;
            for(int j=1; j <= n; j++) 
                if(st[j] == false && (t == -1 || dist[t] > dist[j]))
                    t = j;
            st[t] = true;
            for(int j=1; j <= n; j++) {
                if(g[t][j] != -1)
                    dist[j] = Math.min(dist[j], dist[t] + g[t][j]);
            }
        }
    }
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(), m = sc.nextInt();
        int[][] g = new int[n+1][n+1];
        int[] dist = new int[n+1];
        for(int i=0; i <= n; i++) 
            for(int j=0; j <= n; j++) 
                if(i == j) g[i][i] = 0;
                else g[i][j] = -1;
        for(int i=0; i < m; i++){
            int x = sc.nextInt(), y = sc.nextInt(), z = sc.nextInt();
            if(x != y)
                g[x][y] = g[x][y] == -1 ? z : Math.min(g[x][y], z);
        }
        Arrays.fill(dist, Integer.MAX_VALUE);
        dijkstra(g, dist, n, 1);
        if(dist[n] == Integer.MAX_VALUE)
            System.out.println(-1);
        else
            System.out.println(dist[n]);
    }
}
原文地址:https://www.cnblogs.com/lixyuan/p/13289409.html