zoukankan      html  css  js  c++  java
  • 最短路算法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]);
        }
    }
    
  • 相关阅读:
    USACO 之 Section 2.2 (已解决)
    USACO 之 Section 2.1 (已解决)
    《C++ Primer》学习 之 函数指针相关用法
    《C++ Primer》学习 之 const_cast使用
    《C++ Primer》学习 之 返回数组的引用(返回数组的指针,方法与之相同)
    USACO 之 Section 1.5 (已解决)
    USACO 之 Section 1.4 More Search Techniques (已解决)
    [NN] 对于BackPropagation(BP, 误差反向传播)的一些理解
    [CLPR] 定位算法探幽
    [LeetCode系列] 双单链表共同节点搜索问题
  • 原文地址:https://www.cnblogs.com/lixyuan/p/13289409.html
Copyright © 2011-2022 走看看