【贪心算法】Dijkstra 算法及其衍生

目录

  • Dijkstra 算法
  • Dijkstra 算法正确性
    • 证明
  • Dijkstra 算法的复杂度
    • 优化
  • Dijkstra 算法的衍生
  • SSSP的应用

Dijkstra 算法

1959 年,Edsger Dijkstra 提出一个非常简单的贪心算法来求解单源最短路径问题(Single-Source Shortest Path,SSSP)。

我们开始来描述这个算法,它确定从源点s 到图的每个其他结点的最短路径的长度,同时也容易确定这些路径。算法维护结点的集合 S S S ,对于这些结点我们已经确定了从 s 出发的最短距离 d(u)

  1. 这是图“已被探查”的部分初始: S = { s } S=\{s\} S={s} ,且 d ( s ) = 0 d(s)=0 d(s)=0

  2. 现在对每个结点 v ∈ V − S v\in V-S vVS 我们确定一条最短路径,它可以沿一条穿过已被探查部分 S 的路径旅行到某个 u ∈ S u\in S uS ,然后再沿着一条边 ( u , v ) (u,v) (u,v) 而把这条路径构造出来,即我们考虑量 d ′ ( v ) = min ⁡ e = ( u , v ) : u ∈ S d ( u ) + l e d'(v)=\min_{e=(u,v):u\in S}d(u)+l_e d(v)=mine=(u,v):uSd(u)+le

  3. 我们选择结点 v ∈ V − S v\in V-S vVS 使得这个量最小,将 v v v 加到 S S S 中,并且定义 d ( v ) d(v) d(v) d ′ ( v ) d'(v) d(v)的值。

在这里插入图片描述

生成与 Dijkstra 算法找到的距离相对应的 s➡u 路径 P u P_u Pu 是简单的:

  • 当每个结点 v v v 被加到集合 S S S 时,只需要记录一条达到值 min ⁡ e = ( u , v ) : u ∈ S d ( u ) + l e \min_{e=(u,v):u\in S}d(u)+l_e mine=(u,v):uSd(u)+le 的边 ( u , v ) (u,v) (u,v)
    路径 P v P_v Pv 隐含地由这些边描绘出来:
    • 为构造 P_v,我们只不过从 v v v 开始,沿反方向跟随对 v v v 存入的边到 u u u
      然后沿反方向跟随对 u u u 存入的边到它的祖先,并且继续下去直到我们到达源点 s s s

Dijkstra 算法正确性

证明算法的正确性即证明路径 P u P_u Pu 确实是最短路径

Diikstra 算法在下述意义上是贪心法,我们用一条边加上一支在 S 中的路径总可以构造一支最短的新的 s-v 路径。通过归纳证明它“领先于”所有其他的解,即确定每一次它选了一条到结点 v v v 的路径,这条路径比每条到的其他可能的路径都要短。

证明

通过在 S 的大小上的归纳来证明这个定理;

  • ∣ S ∣ = 1 |S|=1 S=1 此时有 S = s S={s} S=s d ( s ) = 0 d(s)=0 d(s)=0
  • ∣ S ∣ = k , k ≥ 1 |S|=k,k≥1 S=k,k1 时,加入结点 v v v 使得 ∣ S ∣ = k + 1 |S|=k+1 S=k+1 ,令 ( u , v ) (u,v) (u,v) 是路径上的最后一条边

根据归纳假设:路径 P u P_u Pu 是对某个结点 u ∈ S u\in S uS 的最短 s-u 路径
考虑任意其他的 s-v 路径 P P P,要证明它至少与 P v P_v Pv 一样长,为了到达 v v v ,这条路径 P P P 一定在某个地方离开集合 S S S

y y y 是在 P P P 上但不在 S S S 中的第一个结点,且设 x ∈ S x\in S xS 是紧接在 y y y 前面的结点,如下图所示

在这里插入图片描述
证明的关键非常简单: P P P 不可能比 P v P_v Pv 短,因为到它离开集合 S S S 的时刻至少已经与 P v P_v Pv 一样长。在第 k + 1 k+1 k+1 次选代中,Diikstra 算法一定已经考虑过通过边 ( x , y ) (x,y) (x,y) 把结点 y y y 加到 S S S,但是由于 v v v 更有利而放弃了这个选择。这就意味着没有从 s s s 经过到 y y y 且比 P v P_v Pv 更短的路径。同时 P P P 中到 y y y 为止的子路径是至少与 P v P_v Pv 一样长的路径

P ′ P' P 代表 P P P 的从 s s s x x x 的子路径。

  • 因为 x ∈ S x\in S xS ,根据归纳假设 P x P_x Px 是最短的 s-x 路径,且长度为 d ( x ) d(x) d(x) ,因此 l ( P ′ ) ≥ l ( P x ) = d ( x ) l(P')\ge l(P_x)=d(x) l(P)l(Px)=d(x)

  • 于是 P P P 的到结点 y y y 的子路径 l ( P ) l(P) l(P) 有长度 l ( P ′ ) + l ( x , y ) ≥ d ( x ) + l ( x , y ) ≥ d ′ ( y ) l(P')+l(x,y)\ge d(x)+l(x,y) \ge d'(y) l(P)+l(x,y)d(x)+l(x,y)d(y)

  • 因为 Dijkstra 算法在这次迭代中选择了 v v v 而不是 y y y 所以 d ′ ( y ) ≥ d ′ ( v ) = l ( P v ) d'(y)\ge d'(v)=l(P_v) d(y)d(v)=l(Pv)

上述不等式组合起来可证明: l ( P ) ≥ l ( P ′ ) + l ( x , y ) ≥ l ( P v ) l(P)\ge l(P')+l(x,y)\ge l(P_v) l(P)l(P)+l(x,y)l(Pv)


Dijkstra 算法的复杂度

  • 对于具有 n n n 个结点的图:While 循环的迭代有 n − 1 n-1 n1 次,每次迭代把一个新结点 v v v 加到 S S S 中。有效选择正确的结点 v v v 是比较复杂的事情。如果考虑每个结点 v ∈ S v\in S vS 并且检查所有在 S S S v v v 之间的边以确定最小值
  • 对于具有 m m m 条边的图,计算所有这些最小值可能用 O ( m ) O(m) O(m) 时间
  • 运行时间为 O ( m n ) O(mn) O(mn)

优化

对于最小值的确定可以采取一定的优化措施
对每个结点 v ∈ V − S v\in V-S vVS 维护最小值 d ′ ( v ) = min ⁡ e = ( u , v ) , u ∈ S d ( u ) + l e d'(v)= \min_{e=(u,v),u\in S} d(u)+l_e d(v)=mine=(u,v),uSd(u)+le ,而不是在每次迭代时重新计算
同时将 V-S 的结点保存在一个以 d ′ ( v ) d'(v) d(v) 作为其关键字的优先队列里来进一步改进算法的效率

  • 优先队列:用于维护 n 个元素集合的数据结构,每个元素具有一个关键字。一个优先队列可以有效地插入元素、删除元素、改变一个元素的关键字以及取出具有最小关键字的元素。

使用优先队列,Dijkstra 算法可以在具有 n 个结点和 m 条边的图上,实现运行在 O ( m ) O(m) O(m) 时间,加上 n 次 ExtractMin 操作和 m 次ChangeKey 操作的时间.

每个优先队列的操作可以运行在 O ( log ⁡ n ) O(\log n) O(logn) 时间

于是对于这个实现的总时间是 O ( m log ⁡ n ) O(m\log n) O(mlogn)

import heapq

def dijkstra(graph, start):
    distances = {node: float('inf') for node in graph}
    distances[start] = 0
    priority_queue = [(0, start)]

    while priority_queue:
        current_distance, current_node = heapq.heappop(priority_queue)

        if current_distance > distances[current_node]:
            continue

        for neighbor, weight in graph[current_node].items():
            distance = current_distance + weight
            if distance < distances[neighbor]:
                distances[neighbor] = distance
                heapq.heappush(priority_queue, (distance, neighbor))

    return distances

# Example graph
graph = {
    'A': {'B': 4, 'C': 2},
    'B': {'A': 4, 'C': 5, 'D': 10},
    'C': {'A': 2, 'B': 5, 'D': 3},
    'D': {'B': 10, 'C': 3}
}
start_node = 'A'

result = dijkstra(graph, start_node)
print("Shortest distances from node", start_node, "to all other nodes:", result)

Dijkstra 算法的衍生

priority queueINSERTDELETE-MINDECREASE-KEYtotal
Node-indexed array
(A[i] = priority of i)
O ( 1 ) O(1) O(1) O ( n ) O(n) O(n) O ( 1 ) O(1) O(1) O ( n 2 ) O(n^2) O(n2)
Binary heap O ( log ⁡ n ) O(\log n) O(logn) O ( log ⁡ n ) O(\log n) O(logn) O ( log ⁡ n ) O(\log n) O(logn) O ( m log ⁡ n ) O(m\log n) O(mlogn)
D-way heap
(Johnson 1975)
O ( d log ⁡ d n ) O(d\log _dn) O(dlogdn) O ( d log ⁡ d n ) O(d\log _dn) O(dlogdn) O ( log ⁡ d n ) O(\log _dn) O(logdn) O ( m log ⁡ m / n n ) O(m\log _{m/n} n) O(mlogm/nn)
Fibonacci heap
(Fredman–Tarjan 1984)
O ( 1 ) O(1) O(1) O ( log ⁡ n ) O(\log n) O(logn) O ( 1 ) O(1) O(1) O ( m + n log ⁡ n ) O(m+n\log n) O(m+nlogn)
Integer priority queue
(Thorup 2004)
O ( 1 ) O(1) O(1) O ( log ⁡ log ⁡ n ) O(\log \log n) O(loglogn) O ( 1 ) O(1) O(1) O ( m + n log ⁡ log ⁡ n ) O(m+n\log \log n) O(m+nloglogn)

SSSP的应用

  • PERT/CPM(计划评审技术/关键路径法)
  • 地图导航
  • 缝隙雕刻(Seam Carving)
  • 机器人导航
  • 纹理映射
  • LaTeX排版
  • 城市交通规划
  • 电话营销员排班
  • 电信消息路由
  • 网络路由协议(OSPF, BGP, RIP)
  • 根据给定交通拥堵模式的最佳卡车路线

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/297102.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Qt/QML编程学习之心得:Timer的使用(22)

Qt中timer计时器如何使用? Timer的创建: void InitTimer(){myTimer = new QTimer(q);myTimer->setInterval(100); // 100msmyTimer->setSingleShot(true); //只运行一次的计时器QObject::connect(myTimer,SIGNAL(timeout()),q,SLOT(onTimeOut()));myTimer->start(…

网络调试 TCP,开发板用静态地址-入门7

用两台电脑&#xff08;无线网络&#xff09;做实验 1.1, 在电脑A上设置为Server如下&#xff1a; 选择TCP Server后&#xff0c;直接跳出用本机IP做为“本地主机地址” 1.2在 电脑B上设置为Client, 远程主机地址设置为Server的 IP 1.3, 在A, B两台电脑上能够互相发送数据 用…

asp.net core跨域

说明 跨域问题只存在于基于浏览器的 Web 开发中。由于小程序的宿主环境不是浏览器&#xff0c;而是微信客户端&#xff0c;所以小程序中不存在跨域的问题。 Ajax 技术的核心是依赖于浏览器中的 XMLHttpRequest 这个对象&#xff0c;由于小程序的宿主环境是微信客户端&#xff0…

Java面试题之并发

前言 本篇主要总结JAVA面试中关于并发相关的高频面试题。本篇的面试题基于网络整理&#xff0c;和自己编辑。在不断的完善补充哦。 简述程序、进程、线程、的基本概念&#xff1f; 程序 程序&#xff0c;是含有指令和数据的文件&#xff0c;被存储在磁盘或其他的数据存储设备…

亚马逊自养号测评:提升商品排名与流量的必要操作

自养号测评是通过使用自主注册的海外买家账号&#xff0c;对商品进行评价&#xff0c;以提升其在平台上的排名和流量的操作。卖家选择自养号这种方式来增强商品的曝光度和吸引更多潜在买家。然而&#xff0c;养号并非易事&#xff0c;需要卖家提高养号技术、掌握相应技巧&#…

2024最新Selenium面试题,建议收藏备用!

一.你在TestNG中使用了哪些注解&#xff1f; Test BeforeSuite AfterSuite BeforeTest AfterTest BeforeClass AfterClass BeforeMethod AfterMethod 二.如何从Excel中读取数据&#xff1f; FileInputStream fs new FileInputStream(“excel文件路径”); Workbook …

李宏毅机器学习第二十四周周报 Self-attention ConvLSTM

文章目录 week 24 Self-attention ConvLSTM for Spatiotemporal Prediction摘要Abstract一、机器学习二、文献阅读1. 题目2. abstract3. 网络架构3.1基础模型3.2自注意力记忆模块3.3Self-Attention ConvLSTM 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1实现4.3.2数…

[C#]使用onnxruntime部署yolov8-onnx印章检测

【官方框架地址】 https://github.com/ultralytics/ultralytics.git 【算法介绍】 YOLOv8是目标检测领域中的一种先进算法&#xff0c;它是YOLO&#xff08;You Only Look Once&#xff09;系列算法的最新发展。YOLO算法以其高效和实时的性能而著名&#xff0c;而YOLOv8则进一…

数字藏品如何赋能线下实体?以 BOOMSHAKE 潮流夜店为例

此篇为报告内容精华版&#xff0c;更多详细精彩内容请点击 完整版 在数字化浪潮的推动下&#xff0c;品牌和企业正在迎来一场前所未有的变革。传统市场营销策略逐渐让位于新兴技术&#xff0c;特别是非同质化代币&#xff08;NFT&#xff09;的应用。这些技术不仅改变了品牌资…

c++ spdlog日志系统

非常好用的日志系统 最近用oatpp写webapi&#xff0c;但他的日志只是显示在控制台&#xff0c;并不记录到文件。 做接口的&#xff0c;肯定要记录错误日志&#xff0c;好查找问题 于是用spdlog&#xff0c;不用编译dll或lib&#xff0c; include 头文件就直接使用了&#x…

Redis基础学习一

1. Redis 入门 1.1. Redis 诞生历程 1.1.1.从一个故事开始 08 年的时候有一个意大利西西里岛的小伙子&#xff0c;笔名 antirez&#xff08;http://invece.org/&#xff09;&#xff0c;创建了一个访客信息网站 LLOOGG.COM。有的时候我们需要知道网站的访问情况&#xff0c;…

Anaconda + Pytorch 超详细安装教程

Anaconda Pytorch 超详细安装教程 安装 Anaconda 略,自行百度即可 安装 Pytorch 虚拟环境 第一步 选择 env第二步 创建第三步 填写环境名称和选择 python 版本号 第四步 打开 https://pytorch.org/ 选择 pytorch 版本&#xff0c;我这里选择的是 GPU 版本 即 CUDA 11.8,也…

C语言学习NO.13-字符函数(三)-strncpy,strncat,strncmp长度受限制的字符串函数

长度受限制的字符串函数介绍 一、strncpy函数的使用 &#xff08;一&#xff09;strncpy使用 #include <stdio.h> #include <string.h>int main() {char arr1[20] "asdfgdfv";char arr2[7] "zxcvbn";strncpy(arr1, arr2, 4);printf("…

B+树索引及其原理

MySQL索引的底层结构是B树&#xff0c;为什么它会选择这个结构&#xff1f;联合索引是怎么实现的&#xff1f;最左侧匹配原则的原理是什么&#xff1f;本文将一一解答这些疑惑。 1 前置知识 在学习B树之前&#xff0c;我们先了解下其他的树形结构&#xff1a;二叉树、平衡二叉…

互联网加竞赛 基于人工智能的图像分类算法研究与实现 - 深度学习卷积神经网络图像分类

文章目录 0 简介1 常用的分类网络介绍1.1 CNN1.2 VGG1.3 GoogleNet 2 图像分类部分代码实现2.1 环境依赖2.2 需要导入的包2.3 参数设置(路径&#xff0c;图像尺寸&#xff0c;数据集分割比例)2.4 从preprocessedFolder读取图片并返回numpy格式(便于在神经网络中训练)2.5 数据预…

Plantuml之nwdiag网络图语法介绍(二十九)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

HTTP协议-Cookie和Session详解

1|0前置&#xff1a; 会话&#xff08;Session&#xff09;跟踪是Web程序中常用的技术&#xff0c;用来跟踪用户的整个会话。常用的跟踪技术就是Cookie和Session。 Cookie通过在客户端记录信息确定用户身份&#xff0c;Session通过在服务器记录确定用户身份。 本章将系统的讲…

我的第一个前端项目,vue项目从零开始创建和运行

​入门前端&#xff0c;从基础做起&#xff0c;从零开始新建项目 背景&#xff1a;VUE脚手架项目是一个“单页面”应用&#xff0c;即整个项目中只有1个网页&#xff01; 在VUE脚手架项目中&#xff0c;主要是设计各个“视图组件”&#xff0c;它们都是整个网页中某个部分&…

养乐多公司确认 95 G 用户私密数据被泄露

一名自称为DragonForce的组织声称已经公开泄露了澳大利亚养乐多公司&#xff08;Yakult Australia&#xff09;的95.19 GB数据。Yakult Australia证实了这次网络攻击的真实性&#xff0c;并表示公司在澳大利亚和新西兰的IT系统都受到了影响。 该公司在一份声明中表示&#xff…

(2024,少样本微调自适应,泛化误差界限,减小泛化误差的措施)多模态基础模型的少样本自适应:综述

Few-shot Adaptation of Multi-modal Foundation Models: A Survey 公和众和号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 2. 多模态基础模型的预训练 3. 多模态基础模…