Java中的 Dijkstra 算法

Java中的 Dijkstra

应用场景

用于求单源最短路径(非负权图),其贪心策略是:"每次从未确定最短路的点中,选出当前距离起点最近的点,用它去更新邻居。"我们使用邻接表去储存图,一般都是有向图,只需要进行一次添加就可以,每个节点我们使用数组 int[] 存储,也可以自定义一个类去存储。

优先队列(PriorityQueue)

这里涉及到数据结构中的一个概念------堆,堆有最小堆和最大堆,我们 Dijkstra 算法使用的是最小堆,而优先队列创建的是最大堆,这时候我们就要做一些处理。

  • 原始创建------最大堆:
    PriorityQueue <Integer> PQ = new PriorityQueue<>();
  • 变式创建------最小堆:
    PriorityQueue <Integer> PQ = new PriorityQueue<>(Collections.reverseOrder());(仅用于最大变最小)
    或者 PriorityQueue <Integer> PQ = new PriorityQueue<>((a,b)->Integer.compare(a,b));
    或者PriorityQueue <Integer> PQ = new PriorityQueue<>(Integer::compareTo);
  • 常用函数(和队列是一样的)
    PQ.offer():入队
    PQ.poll():出队
    PQ.peek():查看
    PQ.isEmpty():检查是否为空
    唯一区别是优先队列没有remove(删除)

整数快读函数

代码实现(之前的基础快读next()函数因为新建了很多字符串用于中转,所以内存会爆,可以先试)

java 复制代码
 static int readInt(BufferedReader bf)throws IOException{
        int c,n =0;
        boolean neg = false;//接收该数字是否为负,如果确保是非负的数据,可以省略
        while((c = bf.read())<=' ')//制表符,换行符,空格之类的分割符的ASC码都小于空格
            if(c == -1)//-1代表数据结束
                return -1;
        if(c=='-'){//如果是负数
            neg = true;
            c = bf.read();
        }
        do{
            n = n*10+c-'0';
        }while((c = bf.read())>' ');
            return neg ? -n:n;//返回正数或者负数
    }

例题(FROM 洛谷 P3371)

思路

1.创建一个dist数组存储起点到该点的最短距离,其实有点像dp了,然后不断更新这个最短距离,最后输出

2.其实这个题除了整数快读函数还有一个解决办法,就是将输出用StringBuilder存储,只调用一次print函数,因为print函数也会导致缓存堆积,最终内存超限。(蒽。。。我刚才去试了一下,改输出的方法还是会有三个MLE)

代码实现

java 复制代码
import java.util.*;
import java.io.*;

public class Main{
    static final int INT =  Integer.MAX_VALUE;
    static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    public static void main(String [] args) throws IOException{
        int n = readInt(bf);
        int m = readInt(bf);
        int s = readInt(bf);
        int [] dist = new int[n+1];
        Arrays.fill(dist,INT);
        dist[s] = 0;
        List <List<int[]>>list = new ArrayList<>(n+1);
        for(int i=0;i<=n;i++)
            list.add(new ArrayList<>());
        for(int i=0;i<m;i++){
            int u = readInt(bf);
            int v = readInt(bf);
            int w = readInt(bf);
            list.get(u).add(new int[]{v,w});
        }
        //int [] = {dist,node};
        PriorityQueue<int[]> pq = new PriorityQueue<>((a,b)->Integer.compare(a[0],b[0]));//min_PQ
        pq.offer(new int [] {0,s});
        while(!pq.isEmpty()){
            int [] cur = pq.poll();
            int d = cur[0];
            int cu = cur[1];
            if(d!=dist[cu]) continue;
            for(int [] edge:list.get(cu)){
                int v = edge[0];
                int w = edge[1];
                int newdist = d+w;
                if(newdist<dist[v]){
                    dist[v] = newdist;
                    pq.offer(new int []{newdist,v});
                }
            }
        }
        for(int i=1;i<=n;i++)
            System.out.print(dist[i]+" ");
    }
    static int readInt(BufferedReader bf)throws IOException{
        int c,n =0;
        boolean neg = false;
        while((c = bf.read())<=' ')
            if(c == -1)
                return -1;
        if(c=='-'){
            neg = true;
            c = bf.read();
        }
        do{
            n = n*10+c-'0';
        }while((c = bf.read())>' ');
            return neg ? -n:n;
    }
}

注意:即使题里没说也要将dist全部初始化为 Integer.MAX_VALUE,否则会导致输出全为0------没有比0更小的了。
进阶训练:洛谷 P4779(这个不用整数快读,直接快读就能过,其他都一样)

例题2(FROM 洛谷 P1144)

该题融合了 dp 和 Dijkstra 和 BFS

代码实现

java 复制代码
import java.util.*;
import java.io.*;

public class Main{
    static int MOD = 100003;
    static BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
    static StringTokenizer st;
    public static void main(String [] args)throws IOException{
        int n = Integer.parseInt(next()); //node 节点
        int m = Integer.parseInt(next());//edge 边
        List<List<Integer>> list = new ArrayList<>(n+1);
        for(int i=0;i<=n;i++)
            list.add(new ArrayList<>());
        for(int i=0;i<m;i++){
            int x = Integer.parseInt(next());
            int y = Integer.parseInt(next());
            if(x==y)//自环
                continue;
            else{
                list.get(x).add(y);
                list.get(y).add(x);
            }
        }
        int [] dp = new int [n+1];
        //dp[i] 表示顶点1到顶点i有多少条不同的最短路
        int [] dist = new int [n+1];
        //dist[i] 表示起点到该点的最短距离
        Arrays.fill(dist,-1);
        //dist [i] = -1 代表未达
        dist[1] = 0;
        dp[1] = 1;
        
        Queue<Integer> q = new ArrayDeque<>();
        q.offer(1);//第一个节点
        
        while(!q.isEmpty()){
            int u = q.poll();
            for(int v : list.get(u)){//遍历该节点的邻居
                if(dist[v] == -1){
                    dist[v] = dist[u] + 1;
                    dp[v] = dp[u];
                    q.offer(v);
                }
                else if(dist[v] == dist[u] + 1)
                //如果该点的邻居等于该点离起点的最小距离再走一步,那该邻居也是最小距离
                    dp[v] = (dp[v] + dp[u])% MOD;
            }
        }
        StringBuilder sb = new StringBuilder();//如果不用这个的话,会有一个TLE
        for(int i=1;i<=n;i++){
            sb.append(dp[i]);
            sb.append("\n");
        }
        System.out.print(sb);
    }
    static String next() throws IOException{
        while(st== null||!st.hasMoreTokens()){
            String str = bf.readLine();
            if(str == null) return null;
            st = new StringTokenizer (str);
        }
        return st.nextToken();
    }
}
相关推荐
靴子学长1 天前
Decoder only 架构下 - KV cache 的理解
pytorch·深度学习·算法·大模型·kv
sjmaysee1 天前
Java框架SpringBoot(一)
java·开发语言·spring boot
寒秋花开曾相惜1 天前
(学习笔记)3.8 指针运算(3.8.3 嵌套的数组& 3.8.4 定长数组)
java·开发语言·笔记·学习·算法
Гений.大天才1 天前
2026年计算机领域的年度主题与范式转移
算法
想唱rap1 天前
Linux线程
java·linux·运维·服务器·开发语言·mysql
golang学习记1 天前
IDEA 2026.1官宣:AI 建议免费了!
java·ide·intellij-idea
njidf1 天前
C++与Qt图形开发
开发语言·c++·算法
ZoeJoy81 天前
算法筑基(一):排序算法——从冒泡到快排,一文掌握最经典的排序算法
数据结构·算法·排序算法
qwehjk20081 天前
代码动态生成技术
开发语言·c++·算法
cccccc语言我来了1 天前
Linux(9)操作系统
android·java·linux