蓝桥杯 Java B 组之最短路径算法(Dijkstra、Floyd-Warshall)

news/2025/2/26 3:50:25

Day 2:最短路径算法(Dijkstra、Floyd-Warshall)


📖 一、最短路径算法简介

最短路径问题是图论中的经典问题,主要用于求解 单源最短路径多源最短路径。在实际应用中,最短路径广泛应用于 导航系统、网络路由、任务调度 等场景。

📌 最短路径算法分类

算法适用场景时间复杂度
Dijkstra单源最短路径(无负权)O((V+E) logV)(使用优先队列优化)
Floyd-Warshall多源最短路径O(V³)
Bellman-Ford处理负权边的单源最短路径O(VE)

📖 二、Dijkstra 算法(单源最短路径)

适用范围

  • 适用于无负权边单源最短路径问题。
  • 主要思想是:使用 贪心 + 优先队列 找到当前最短的路径

🔹 1. 题目:网络延迟时间(Leetcode 743)

题目描述: 给定 n 个节点的有向图,边 times[i] = (u, v, w) 表示从 uv 的边权为 w。从源点 k 发送信号,计算所有节点都收到信号的最短时间,若无法到达所有节点,返回 -1

示例

输入: times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
输出: 2

🔹 2. 思路

  • 使用 Dijkstra 算法,**优先队列(最小堆)**优化时间复杂度。
  • 维护 dist[] 数组,dist[i] 代表从 ki 的最短路径。
  • 使用 最小堆(PriorityQueue) 维护当前最短路径的节点,每次弹出最短路径节点,更新其邻接点。

🔹 3. 代码实现

import java.util.*;

public class DijkstraNetworkDelay {
    public int networkDelayTime(int[][] times, int n, int k) {
        // 图的邻接表
        Map<Integer, List<int[]>> graph = new HashMap<>();
        for (int[] edge : times) {
            graph.putIfAbsent(edge[0], new ArrayList<>());
            graph.get(edge[0]).add(new int[]{edge[1], edge[2]});
        }

        // 最小堆(按路径权值排序)
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[1]));
        pq.offer(new int[]{k, 0}); // 从源点 k 开始
        Map<Integer, Integer> dist = new HashMap<>();

        while (!pq.isEmpty()) {
            int[] cur = pq.poll();
            int node = cur[0], time = cur[1];

            if (dist.containsKey(node)) continue; // 已访问
            dist.put(node, time);

            if (!graph.containsKey(node)) continue;
            for (int[] next : graph.get(node)) {
                int neighbor = next[0], weight = next[1];
                if (!dist.containsKey(neighbor)) {
                    pq.offer(new int[]{neighbor, time + weight});
                }
            }
        }

        if (dist.size() < n) return -1; // 说明有节点不可达
        return Collections.max(dist.values()); // 返回最长的最短路径
    }

    public static void main(String[] args) {
        DijkstraNetworkDelay solution = new DijkstraNetworkDelay();
        int[][] times = {{2,1,1},{2,3,1},{3,4,1}};
        int n = 4, k = 2;
        System.out.println(solution.networkDelayTime(times, n, k)); // 输出 2
    }
}

🔹 4. 代码讲解

  1. 构建邻接表:用 Map<Integer, List<int[]>> 存储 邻接节点和权重
  2. 使用优先队列(最小堆):每次取出当前路径最短的节点进行扩展,更新邻接点的最短路径。
  3. 利用 dist[] 数组:记录从 k 到各个节点的最短路径。
  4. 时间复杂度
    • O((V+E) logV)(优先队列优化)。
    • 其中 V 是顶点数,E 是边数。

📖 三、Floyd-Warshall 算法(多源最短路径)

适用范围

  • 适用于多源最短路径问题。
  • 允许 负权边(但不能有负权环)。
  • 主要思想是:动态规划,每次考虑是否经过某个中间点 k 能让路径更短

🔹 1. 题目:2019 省赛 - 迷宫

题目描述: 给定一个 n × n 的迷宫,1 表示墙,0 表示可通行。求从起点 (0,0) 到终点 (n-1,n-1)最短路径

输入示例

4
0 0 1 0
1 0 1 0
1 0 0 0
1 1 1 0

输出

5

(路径 [(0,0) -> (1,1) -> (2,1) -> (2,2) -> (2,3) -> (3,3)]


🔹 2. 思路

  1. 转换为图问题:迷宫是一个 n × n 的无向图,连通区域是 可通行的 0
  2. 使用 Floyd-Warshall 算法
    • dist[i][j] 存储 (0,0)(i,j) 的最短路径
    • grid[i][j] == 1,设 dist[i][j] = ∞(墙)。
    • dist[i][j] = min(dist[i][j], dist[k][m] + 1),其中 (k,m) 是邻居。

🔹 3. 代码实现

import java.util.*;

public class FloydWarshallMaze {
    static final int INF = 10000; // 设定一个较大的数表示不可达
    static int[][] dist;
    static int[][] directions = {{1,0}, {0,1}, {-1,0}, {0,-1}}; // 上下左右四个方向

    public static int shortestPath(int[][] maze) {
        int n = maze.length;
        dist = new int[n][n];

        // 初始化距离数组
        for (int i = 0; i < n; i++) {
            Arrays.fill(dist[i], INF);
        }
        dist[0][0] = 0; // 起点

        // Floyd-Warshall 核心算法
        for (int k = 0; k < n; k++) { // 中间点
            for (int i = 0; i < n; i++) { // 起点
                for (int j = 0; j < n; j++) { // 终点
                    if (maze[i][j] == 0) {
                        for (int[] dir : directions) {
                            int x = i + dir[0], y = j + dir[1];
                            if (x >= 0 && x < n && y >= 0 && y < n && maze[x][y] == 0) {
                                dist[x][y] = Math.min(dist[x][y], dist[i][j] + 1);
                            }
                        }
                    }
                }
            }
        }

        return dist[n-1][n-1] == INF ? -1 : dist[n-1][n-1];
    }

    public static void main(String[] args) {
        int[][] maze = {
            {0, 0, 1, 0},
            {1, 0, 1, 0},
            {1, 0, 0, 0},
            {1, 1, 1, 0}
        };
        System.out.println(shortestPath(maze)); // 输出 5
    }
}

📖 四、总结

Dijkstra vs Floyd-Warshall

算法适用范围时间复杂度
Dijkstra单源最短路径O((V+E) logV)
Floyd-Warshall多源最短路径O(V³)

🎯 练习建议

  • 熟练掌握 Dijkstra + 优先队列优化(最小堆 PriorityQueue)。
  • 理解 Floyd-Warshall 多源最短路径的动态规划思想


http://www.niftyadmin.cn/n/5867142.html

相关文章

【Java项目】基于Spring Boot的火车订票管理系统

【Java项目】基于Spring Boot的火车订票管理系统 技术简介&#xff1a;采用Spring Boot框架、Java技术、MySQL数据库等实现。 系统简介&#xff1a;火车订票管理系统是一个面向管理员和用户的在线订票平台&#xff0c;主要分为前台和后台两大模块。前台功能模块包括&#xff08…

WPS中Word表格做好了,忘记写标题了怎么办?

大家好&#xff0c;我是小鱼。 在使用wps制作Word表格时经常会遇到这种情况&#xff0c;就是辛辛苦苦把word表格制作好了&#xff0c;却突然发现忘了为表格添加标题了。怎么都没法为表格重写添加标题&#xff0c;真是一阵操作猛如虎&#xff0c;结果觉得表格真是白做了。其实&…

设计模式教程:备忘录模式(Memento Pattern)

备忘录模式&#xff08;Memento Pattern&#xff09;详解 一、模式概述 备忘录模式&#xff08;Memento Pattern&#xff09;是一种行为型设计模式&#xff0c;允许在不暴露对象实现细节的情况下&#xff0c;保存对象的内部状态&#xff0c;并在需要时恢复该状态。备忘录模式…

Qt开发⑦Qt的窗口_上_菜单栏+工具栏+状态栏

目录 1. 菜单栏 1.1 创建菜单栏 1.2 在菜单栏中添加菜单 1.3 创建菜单项 1.4 在菜单项之间添加分割线 1.5 添加快捷键 1.6 添加子菜单 1.7 添加图标 1.8 综合示例 2. 工具栏 2.1 创建工具栏 2.2 设置停靠位置 2.3 设置浮动属性 2.4 设置移动属性 2.5 综合示例 …

机器学习数学基础:34.点二列

点二列相关教程 一、点二列相关的定义 点二列相关是一种统计方法&#xff0c;用于衡量两个变量之间的相关程度。在这种相关分析中&#xff0c;一个变量是正态连续性变量&#xff0c;取值可以是连续的数值&#xff0c;比如身高、体重、考试分数等&#xff1b;另一个是真正的二…

Android之图片保存相册及分享图片

文章目录 前言一、效果图二、实现步骤1.引入依赖库2.二维码生成3.布局转图片保存或者分享 总结 前言 其实现在很多分享都是我们自定义的&#xff0c;更多的是在界面加了很多东西&#xff0c;然后把整个界面转成图片保存相册和分享&#xff0c;而且现在分享都不需要第三方&…

【代码随想录】第九章-动态规划(上)

【代码随想录】第九章-动态规划&#xff08;上&#xff09; 第九章 动态规划-上1 斐波那契数列509.斐波那契数列Method1&#xff1a;递归Method2&#xff1a;动态规划 70.爬楼梯746.使用最小花费爬楼梯 2 不同路径62.不同路径63.不同路径II 3 整数拆分343.整数拆分96.不同的二叉…

Unity Shader 学习13:屏幕后处理 - 使用高斯模糊的Bloom辉光效果

目录 一、基本的后处理流程 - 以将画面转化为灰度图为例 1. C#调用shader 2. Shader实现效果 二、Bloom辉光效果 1. 主要变量 2. Shader效果 &#xff08;1&#xff09;提取较亮区域 - pass1 &#xff08;2&#xff09;高斯模糊 - pass2&3 &#xff08;3&#xff…