java---堆优化Dijkstra算法---最短路(2)(每日一道算法2022.8.28)

注意事项:
在学习堆优化版的Dijkstra之前,请确定您理解朴素版的Dijkstra
可以看我之前的文章:java-朴素Dijkstra
同时涉及到一些单链表数组模拟的知识:java-单链表数组模拟
我们是使用多个单链表来存储邻接图

一般来说,堆优化Dijkstra用于求稀疏图的最短路,而朴素Dijkstra用于求稠密图的最短路

题目
给定一个 n 个点 m 条边的有向图,图中可能存在重边和自环,所有边权均为非负值
请你求出 1 号点到 n 号点的最短距离,如果无法从 1 号点走到 n 号点,则输出 −1

第一行包含整数 n 和 m
接下来 m 行每行包含三个整数 x,y,z,表示存在一条从点 x 到点 y 的有向边,边长为 z

输入:
3 3
1 2 2
2 3 1
1 3 4
输出:
3
public class 最短路_堆优化Dijkstra_稀疏图 {
    //h,e,ne模拟邻接图,w存储边的权重,dist存储起点到当前节点的距离,st判断节点是否有最短路
    //heap是用优先队列表示堆,我们这里用int数组来模拟pair数据结构,分别是节点编号和节点到起点的距离,然后根据节点距离重写PriorityQueue的Comparator方法
    public static int N = 1000010, index = 0, n, m;
    public static int[] h = new int[N], e = new int[N], ne = new int[N], w = new int[N];
    public static int[] dist = new int[N];
    public static boolean[] st = new boolean[N];
    public static PriorityQueue<int[]> heap = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));

    public static void main(String[] args) {
        //初始化,链表head全部为正无穷,n是点的个数,m是边的个数
        Scanner in = new Scanner(System.in);
        n = in.nextInt(); m = in.nextInt();
        Arrays.fill(h, -1);

        while (m-- > 0){
            int a = in.nextInt(), b = in.nextInt(), c = in.nextInt();
            add(a, b, c);
        }

        System.out.println(dijkstra());
    }
	
	//邻接表的插入操作,类似于单链表模拟
    public static void add(int a, int b, int c) {
        e[index] = b;
        w[index] = c;
        ne[index] = h[a];
        h[a] = index++;
    }

    public static int dijkstra() {
        //dist填充正无穷,dist起点也就是节点1设置为0,到自己肯定是0嘛,然后把节点编号和节点到起点的距离存入堆中
        Arrays.fill(dist, 0x3f3f3f3f);
        dist[1] = 0;
        heap.add(new int[] {1, 0});

        //这里类似BFS宽搜
        while (heap.size() > 0) {
            int[] t = heap.poll();
            //用ver拿到每次的节点下标,distance表示节点到起点的距离,并且用st标记ver已经走过
            int distance = t[1], ver = t[0];
            if (st[ver]) continue;
            st[ver] = true;

            //每次用ver来对其他点更新距离
            for (int i = h[ver]; i!=-1; i = ne[i]) {
                int j = e[i];
                if (dist[j] > distance + w[i]) {
                    dist[j] = distance + w[i];
                    heap.add(new int[] {dist[j], j});
                }
            }
        }

        //如果是正无穷代表没走到这个点,说明路走不通,返回-1,否则返回最终点到起点的距离
        if (dist[n] == 0x3f3f3f3f) {return -1;}
        else return dist[n];
    }
}

今天突破更新时间了属于是,主要是刚刚早些时候研究了一道不让开数组的merge sort题
简直魔鬼,花了太多时间,所以更新晚了,见谅

声明:算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流

你可能感兴趣的:(算法,java,算法,开发语言)