目录

1. 什么是赋权最短路径

2. 赋权最短路径中的关键概念

3. Dijkstra 算法的基本思想

4. Dijkstra 算法实现(Java)


1. 什么是赋权最短路径

在图论中,最短路径问题是指在图中寻找两点之间路径总权重最小的路径问题。如果图的每条边都带有权值(weight),这种图称为赋权图(Weighted Graph)。

2. 赋权最短路径中的关键概念

在赋权最短路径算法中,常用的几个重要概念包括:

  • 顶点(Vertex/Node) 图的基本组成元素,用于表示位置或对象。

  • 边(Edge) 顶点之间的连接关系,可能是有向的(Directed)或无向的(Undirected)。

  • 权重(Weight) 与每条边相关联的数值,表示从一个顶点到另一个顶点的“代价”,可能是时间、距离、费用等。

  • 路径(Path) 由一系列顶点和边构成的通路。

  • 路径长度(Path Length) 路径上所有边的权重之和。

  • 前驱节点(Predecessor Node) 在最短路径中,到达某个顶点前的上一个顶点,用于回溯构建路径。

  • 松弛操作(Relaxation) 如果通过某条边能找到更短的路径,则更新目标顶点的最短距离和前驱节点的过程。

3. Dijkstra 算法的基本思想

Dijkstra 算法由 Edsger W. Dijkstra 在 1956 年提出,是解决单源非负权重最短路径问题的经典算法。 其核心思想是:

  1. 初始化

    • 将源点的最短距离设置为 0,其他顶点设置为无穷大(Integer.MAX_VALUE)。

    • 使用一个优先队列按当前已知的最短距离排序。

  2. 迭代选择最近的未处理顶点

    • 从优先队列中取出当前距离最小的顶点 u

    • 将其标记为“已处理”,不再更新它的距离。

  3. 松弛邻居节点

    • 对于 u 的所有邻接顶点 v,计算 uv 的新距离 newDist = dist[u] + weight(u, v)

    • 如果 newDist < dist[v],则更新 dist[v] = newDist,并记录 uv 的前驱节点。

  4. 重复步骤 2 和 3,直到所有顶点都处理完,或者优先队列为空。

算法特性:

  • 时间复杂度:使用优先队列时为 O(E log V),其中 E 是边数,V 是顶点数。

  • 不能处理含有负权边的图(会导致错误结果)。

  • 保证每次取出的顶点,其最短距离已经确定。

4. Dijkstra 算法实现(Java)

下面给出基于上述思路的完整 Java 实现代码,代码中包含了节点(Node)、边(Edge)的数据结构定义,以及 Dijkstra 算法的执行与路径回溯功能。

import java.util.*;class Node {public String name;          // 顶点名称public List<Edge> adj;    // 邻接顶点列表boolean processed;        // 是否已处理public int dist;  // 初始距离设为无穷大public Node preNode;         // 最短路径上的前驱顶点public Node(String name) {this.name = name;this.adj = new ArrayList<>();this.processed = false;this.dist = Integer.MAX_VALUE;this.preNode = null;}// 添加邻接边public void addEdge(Node to, int weight) {this.adj.add(new Edge(this, to, weight));}
}// 边类定义
class Edge {Node from;Node to;   // 目标节点int weight;    // 边权重public Edge(Node from, Node to, int weight) {this.from = from;this.to = to;this.weight = weight;}
}public class GraphShortPath {public static final int INFINITY = Integer.MAX_VALUE;/*** 计算单源无权最短路径* @param source 源顶点*/public static void unweighted(Node source) {Queue<Node> queue = new LinkedList<>();source.dist = 0;             // 源点距离设为0queue.add(source);               // 源点入队while (!queue.isEmpty()) {Node current = queue.poll();// 遍历所有邻接顶点for (Edge edge : current.adj) {Node neighbor = edge.to;// 如果顶点未被访问过if (neighbor.dist == INFINITY) {neighbor.dist = current.dist + 1;    // 更新距离neighbor.preNode = current;             // 记录路径queue.add(neighbor);               // 邻接点入队}}}}/*** Dijkstra 算法 计算 单源赋权最短路径* @param source*/public static void dijkstra(Node source) {PriorityQueue<Node> queue = new PriorityQueue<>(Comparator.comparingInt(node -> node.dist));source.dist = 0;queue.add(source);while (!queue.isEmpty()) {Node current = queue.poll();if (current.processed) continue;current.processed = true;for (Edge edge : current.adj) {Node neighbor = edge.to;if (neighbor.processed) continue;long newDist = (long) current.dist + edge.weight;if (newDist > Integer.MAX_VALUE) continue;if (newDist < neighbor.dist) { // 发现更短路径则更新 neighbor.dist = (int) newDist;neighbor.preNode = current;queue.add(neighbor);}}}}/*** 重构从源点到目标顶点的最短路径* @param to 目标顶点* @return 路径顶点列表*/public static List<Node> reconstructPath(Node to) {List<Node> path = new ArrayList<>();// 如果目标顶点不可达if (to.dist == INFINITY) {return path;}// 从目标顶点回溯到源顶点for (Node v = to; v != null; v = v.preNode) {path.add(v);}// 反转路径:从源顶点到目标顶点Collections.reverse(path);return path;}/*** 打印最短路径结果* @param vertices 顶点列表*/public static void printResults(List<Node> vertices) {System.out.println("顶点\t距离\t前驱\t路径");System.out.println("--------------------------------------");for (Node v : vertices) {System.out.printf("%s\t%d\t%s\t",v.name,v.dist,(v.preNode != null) ? v.preNode.name : "null");// 打印路径List<Node> path = reconstructPath(v);if (path.isEmpty()) {System.out.print("不可达");} else {for (int i = 0; i < path.size(); i++) {if (i > 0) System.out.print(" → ");System.out.print(path.get(i).name);}}System.out.println();}}// 测试用例public static void main(String[] args) {// 创建顶点Node v1 = new Node("图书馆");Node v2 = new Node("教学楼A");Node v3 = new Node("教学楼B");Node v4 = new Node("食堂");Node v5 = new Node("体育馆");Node v6 = new Node("宿舍");Node v7 = new Node("校门");// 构建校园地图的无向图v1.addEdge(v2,5);v1.addEdge(v4,1);v2.addEdge(v1,2);v2.addEdge(v3,3);v2.addEdge(v5,5);v3.addEdge(v2,4);v3.addEdge(v6,3);v4.addEdge(v1,3);v4.addEdge(v5,5);v4.addEdge(v7,2);v5.addEdge(v2,1);v5.addEdge(v4,1);v5.addEdge(v6,3);v6.addEdge(v3,2);v6.addEdge(v5,3);v6.addEdge(v6,4);v7.addEdge(v4,2);v7.addEdge(v6,2);List<Node> campus = Arrays.asList(v1, v2, v3, v4, v5, v6, v7);// 从图书馆出发计算最短路径
//        unweighted(v1);// 从图书馆出发计算最短路径dijkstra(v1);// 打印结果printResults(campus);// 额外测试:从图书馆到校门的最短路径System.out.println("\n从图书馆到校门的最短路径:");List<Node> pathToGate = reconstructPath(v7);for (Node v : pathToGate) {System.out.print(v.name + (v != v7 ? " → " : ""));}}
}
  • 运行结果

顶点    距离    前驱    路径
--------------------------------------
图书馆    0    null    图书馆
教学楼A    5    图书馆    图书馆 → 教学楼A
教学楼B    7    宿舍    图书馆 → 食堂 → 校门 → 宿舍 → 教学楼B
食堂    1    图书馆    图书馆 → 食堂
体育馆    6    食堂    图书馆 → 食堂 → 体育馆
宿舍    5    校门    图书馆 → 食堂 → 校门 → 宿舍
校门    3    食堂    图书馆 → 食堂 → 校门从图书馆到校门的最短路径:
图书馆 → 食堂 → 校门

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/93099.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/93099.shtml
英文地址,请注明出处:http://en.pswp.cn/web/93099.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Lua】题目小练9

题目&#xff1a;实现一个简单的“银行账户”类要求&#xff1a;使用 元表 模拟面向对象。支持以下功能&#xff1a;Account:new(owner, balance) 创建账户&#xff08;初始余额可选&#xff0c;默认为 0&#xff09;。deposit(amount) 存款&#xff08;不能为负数&#xff09;…

【二分图】染色问题

核心思想&#xff1a;为每一个未染色的&#xff0c;对它自己和它的邻居进行染色&#xff0c;看是否会出现冲突时间复杂度O&#xff08;nm&#xff09;#include<bits/stdc.h> using namespace std; using lllong long; const int N200010; int n,m; vector<int>edge…

报数游戏(我将每文更新tips)

今日tips&#xff1a;报数游戏题目描述报数游戏的游戏规则如下&#xff1a;对一个区间内的整数进行报数&#xff0c;若遇到的数字是质数或个位数是 1&#xff0c;则不报数&#xff0c;输出 pass。 给定开始游戏的第一个整数 a&#xff0c;及结束游戏时的最后一个整数 b&#xf…

大模型开发 - 基于Spring AI 借助MCP Client 通过STDIO和SSE协议调用MCP Server (上)

文章目录概述MCP协议&#xff1a;为AI应用连接外部世界的桥梁MCP Server&#xff1a;上下文与能力的提供者基于Spring AI 1.0.0的开发之路1. 使用Spring AI构建MCP客户端2. 使用Spring AI构建MCP服务器Mcp Client 实战整体架构概览技术栈Codepom配置mcp servers(sse&stdio)…

分析三个文件--启动文件、链接文件、map文件

目录 启动文件 链接文件 部分map文件内容 FLASH物理地址(0x08000000开始)的映射关系 0x08000000 之前地址空间 启动文件 ;******************** (C) COPYRIGHT 2016 STMicroelectronics ******************** ;* File Name : startup_stm32f40_41xxx.s ;* Author…

从零开始学Python之数据结构(字符串以及数字)

一、字符串 1.1 怎么定义字符串 字符串是Python最常用的数据结构之一。在 Python 里是用于处理文本数据的&#xff0c;比如存储姓名、文章内容等文本信息 。 定义方式&#xff1a; 单引号&#xff1a;用单引号 包裹文本&#xff0c;如 name Alice &#xff0c;单引号内可…

Navicat 全量增量数据库迁移

在使用 Navicat 进行数据库迁移时&#xff0c;除了常见的“全量迁移”&#xff08;一次性迁移所有数据和结构&#xff09;&#xff0c;有时还需要支持 增量迁移&#xff08;只迁移新增或修改的数据&#xff09;。下面我将详细讲解如何通过 Navicat 实现&#xff1a;&#x1f50…

css初学者第五天

<1>css的三大特性1.1 层叠性相同选择器给设置相同的样式&#xff0c;此时一个样式就会覆盖&#xff08;层叠&#xff09;另一份冲突的样式。层叠式主要解决样式冲突的问题。层叠性原则&#xff1a;-样式冲突&#xff0c;遵循的原则是就近原则&#xff0c;哪个样式离结构近…

从神经网络语言模型(NNLM)到Word2Vec:自然语言处理中的词向量学习

语言模型 语言(人说的话)模型(完成某个任务) 任务: 概率评估任务:在两句话中&#xff0c;判断哪句话出现的概率大(哪句话在自然语言中更合理)生成任务:预测词语,我明天要____ 统计语言模型 用统计的方法解决上述的两个任务 核心思想 给定一个词序列&#xff0c;计算该序列出现的…

PID学习笔记5-双环PID

在学习江协科技PID课程时&#xff0c;做一些笔记&#xff0c;对应视频3-1&#xff0c;对应代码&#xff1a;1313-双环PID定速定位置控制-代码封装main.c:#include "stm32f10x.h" // Device header #include "Delay.h" #include "OLE…

C#vb.net中Interlocked类实现原子操作加减计算,涵盖状态切换、计数控制等常见场景

以下是 C# 中使用 int 类型结合 Interlocked 类实现原子操作的完整示例&#xff0c;涵盖状态切换、计数控制等常见场景&#xff1a; 完整代码示例csharp using System; using System.Threading;/// <summary> /// 基于整数类型的原子操作工具类&#xff08;线程安全&am…

RCL 2025 | LLM采样机制的新视角:来自处方性偏移的解释

1. 导读 大型语言模型&#xff08;Large Language Models, LLMs&#xff09;在自主决策场景中的应用日益广泛&#xff0c;它们需要在庞大的行动空间中进行响应采样&#xff08;response sampling&#xff09;。然而&#xff0c;驱动这一采样过程的启发式机制仍缺乏深入研究。本…

08 ABP Framework Blazor UI

ABP Framework Blazor UI 架构 overview ABP Blazor UI 系统构建在 Blazorise 组件库之上&#xff0c;为构建数据驱动应用提供结构化方法&#xff0c;包含 CRUD 操作、主题和本地化的一致模式。 #mermaid-svg-QAvWlELsLhZgYXHu {font-family:"trebuchet ms",verdana,…

JUC学习笔记-----LinkedBlockingQueueConcurrentLinkedQueueCopyOnWriteArrayList

LinkedBlockingQueue基本的入队出队初始化public class LinkedBlockingQueue<E> extends AbstractQueue<E>implements BlockingQueue<E>, java.io.Serializable {// 静态内部类 Node&#xff0c;用于存储队列元素及维护节点间关系static class Node<E>…

小杰python高级(six day)——pandas库

1.数据可视化用于绘制 DataFrame 数据图形&#xff0c;它允许用户直接从 DataFrame 创建各种类型的图表&#xff0c;而不需要使用其他绘图库&#xff08;底层实际上使用了 Matplotlib&#xff09;。&#xff08;1&#xff09;plotDataFrame.plot(*args, **kwargs)功能&#xff…

第十六届蓝桥杯青少组C++省赛[2025.8.9]第二部分编程题(1 、庆典队列)

参考程序&#xff1a;#include <iostream> using namespace std;int main() {int n, A;cin >> n >> A; // 输入&#xff1a;n 和 A&#xff0c;用空格隔开cout << n / A; // 整数相除&#xff0c;自动向下取整return 0; }

C++进阶:智能指针

目录1. RAII与智能指针2. C库中的智能指针2.1 智能指针auto_ptr2.2 智能指针unique_ptr2.3 智能指针shared_ptr3. shared_ptr的循环引用4. 智能指针的定值删除器1. RAII与智能指针 上一篇文章学习了异常相关的知识&#xff0c;其中遗留了一个异常安全相关的问题。那就是异常的抛…

Tkinter 实现按钮鼠标悬浮提示:两种方案(继承Frame与不继承)

在 Tkinter 桌面应用开发中&#xff0c;为按钮添加“鼠标悬浮提示”是提升用户体验的常用功能——无需点击&#xff0c;只需将鼠标挪到按钮上方&#xff0c;就能自动显示按钮功能说明。本文将详细介绍两种实现方案&#xff1a;不继承 Frame 类&#xff08;快速简洁版&#xff0…

20250814 最小生成树总结

引子 啊啊额&#xff0c;从一张图里抽出几条边&#xff0c;组成一棵树&#xff0c;无环n−1n-1n−1条边&#xff0c;就是生成树。那么边权和最小的生成树就叫最小生成树&#xff0c;最大生成树同理。 kruskal最小生成树 要求kruskal最小生成树&#xff0c;我们首先用结构体数组…

数据大集网:实体店获客引流的数字化引擎,解锁精准拓客新密码​

​在实体店面临流量焦虑、获客成本攀升的当下&#xff0c;实体店获客引流工具的重要性愈发凸显。如何在激烈的市场竞争中精准触达目标客户、构建可持续的客流增长模式&#xff1f;数据大集网凭借其创新的智能获客体系与全链路服务能力&#xff0c;正成为万千实体店突破增长瓶颈…