AcWing 算法基础 dijkstra

dijkstra

简介

dijkstra算法是单源最短路径算法。

单源即在一个有向图中,从一个节点出发,算法可求该节点至所有可到达节点的最短路径长度。与之相对的称为非单源最短路,即算法运行一次可求出任意节点至任意可到达节点的最短路长度,其代表是floyd算法。单源最短路有两种常见算法,dijkstra算法和bellman-ford算法。前者只能用于求路径权值全部为非负数的最短路,后者是可以求边权中出现负数的算法。

算法步骤

  1. 将图中的点分为两组,遍历到的为一组s,没有遍历的为另一组t,当前遍历未开始,所以所有节点都在t中
  2. 将出发节点的距离设置为0,其他节点到出发节点的距离设置为无穷大
  3. 寻找在t中寻找距离最少的点,使用该点到其他节点的距离来更新其他节点到出发节点的最短距离,每次更新将该点从t取出,放入s
  4. 当所有点更新完毕后,出发节点到每个节点的最短距离也就找到了。

算法实现1

时间复杂度为O(n^2)

import java.util.*;
public class Main{
    public static final int N = 510;
    public static int[][] gra = new int[N][N];
    public static int[] dist = new int[N];
    public static boolean[] isu = new boolean[N];
    //用于记录最短路径
    public static int[] path = new int[N];
    public static int dijkstra(int begin,int end){
        dist[begin] = 0;
        for(int i = 1; i <= end; i++){
            int t = -1;
            for(int j = 1; j <= end; j++){
                if(!isu[j] && (t == -1 || dist[t]>dist[j])){
                    t = j;
                }
            }
            isu[t] = true;
            for(int j = 1; j <= end; j++){
                if(dist[j] > dist[t]+gra[t][j]){
                    dist[j] = dist[t]+gra[t][j];
                    path[j] = t;
                }
            }
        }
        if(dist[end] == 0x3f3f3f3f) return -1;
        else return dist[end];
    }
    public static void main(String[] args){
        Scanner Reader = new Scanner(System.in);
        for(int i = 0;i < gra.length;i++){
            Arrays.fill(gra[i],0x3f3f3f3f);
        }
        Arrays.fill(dist,0x3f3f3f3f);
        Arrays.fill(path,-1);
        int n = Reader.nextInt(),m = Reader.nextInt();
        while(m-- != 0){
            int a = Reader.nextInt(),b = Reader.nextInt(),c = Reader.nextInt();
            gra[a][b] = Math.min(gra[a][b],c);
        }
        System.out.print(dijkstra(1,n));
        for(int i = 1; i <= n;i++){
            System.out.println(path[i]);
        }
    }
}

算法实现2

由于上述算法每次寻找dist[]的最小值都需要O(n)的时间复杂度,所以我们可以用最小堆保存该图的dist数组,时间复杂度优化为O(m*logn)

import java.util.*;

class Pair implements Comparable<Pair>{
    public int first;
    public int second;
    public Pair(int f,int s){
        first = f;
        second = s;
    }
    @Override
    public int compareTo(Pair p){
        return this.second-p.second;
    }
    @Override
    public String toString(){
        return first+" " + second;
    }
}

class Graph{
    private final int N = 100100;
    private int[] e,ne,h,w,dist;
    private int idx = 0;
    private boolean[] isu = new boolean[N];
    private PriorityQueue<Pair> heap = new PriorityQueue();
    public Graph(){
        e = new int[N];
        ne = new int[N];
        h = new int[N];
        w = new int[N];
        dist = new int[N];
        Arrays.fill(ne,-1);
        Arrays.fill(h,-1);
        Arrays.fill(dist,0x3f3f3f3f);
    }
    public void add(int a, int b, int c){
        e[idx] = b;
        w[idx] = c;
        ne[idx] = h[a];
        h[a] = idx++;
    }
    public int dijkstra(int n){
        dist[1] = 0;
        Pair pt = new Pair(1,0);
        heap.offer(pt);
        while(!heap.isEmpty()){
            Pair pte = heap.poll();
            int te = pte.first;
            int distance = pte.second;
            if(!isu[te]){
                isu[te] = true;
                for(int j = h[te];j!= -1;j = ne[j]){
                    dist[e[j]] = Math.min(dist[e[j]],dist[te]+w[j]);
                    Pair np = new Pair(e[j],dist[e[j]]);
                    heap.offer(np);
                }
            }
        }
        if(dist[n] == 0x3f3f3f3f){
            return -1;
        }else{
            return dist[n];
        }
    }
}
public class Main{
    public static void main(String[] args){
        Scanner Reader = new Scanner(System.in);
        Graph gra = new Graph();
        int n = Reader.nextInt(),m = Reader.nextInt();
        while(m-- != 0){
            int a = Reader.nextInt(),b = Reader.nextInt(),c = Reader.nextInt();
            gra.add(a,b,c);
        }
        System.out.print(gra.dijkstra(n));
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值