本章内容

 继续图的讨论,介绍加权图——提高或降低某些边的权重。

 介绍狄克斯特拉dijstra算法,让你能够找出加权图中前往X的最短路径。

 介绍图中的环,它导致狄克斯特拉算法不管用。


在前一章,你找出了从A点到B点的路径。

这是最短路径,因为段数最少——只有三段,但不一定是最快路径。如果给这些路段加上时间,你将发现有更快的路径。

要找出最快的路径,可使用另一种算法——狄 杰/克 斯特拉算法( Dijkstra’s algorithm)。

狄克斯特拉算法包含4个步骤。

(1) 找出“最便宜”的节点,即可在最短时间内到达的节点。

(2) 更新该节点的邻居的开销,其含义将稍后介绍。

(3) 重复这个过程,直到对图中的每个节点都这样做了。

(4) 计算最终路径。

第一步: 找出最便宜的节点。

你站在起点,不知道该前往节点A还是前往节点B。前往这两

个节点都要多长时间呢?

前往节点A需要6分钟,而前往节点B需要2分钟。至于前往其他节点,你还不知道需要多长时间。那么此时最便宜的节点就是前往节点B。

第二步:计算经节点B前往其各个邻居所需的时间。

你刚找到了一条前往节点A的更短路径!直接前往节点A需要6分钟。

但经由节点B前往节点A只需5分钟!

对于节点B的邻居,如果找到前往它的更短路径,就更新其开销。(这里更新的是到节点A的距离)

现在:

 前往节点A的更短路径(时间从6分钟缩短到5分钟);

 前往终点的更短路径(时间从无穷大缩短到7分钟)。

第三步:重复!

重复第一步: 找出可在最短时间内前往的节点。你对节点B执行了第二步,除节点B外,可

在最短时间内前往的节点是节点A。

重复第二步:更新节点A的所有邻居的开销。

你发现前往终点的时间为6分钟!

你对每个节点都运行了狄杰斯特拉算法(无需对终点这样做)。现在,你知道:

 前往节点B需要2分钟;

 前往节点A需要5分钟;

 前往终点需要6分钟。

最后一步——计算最终路径将留到下一节去介绍,这里先直接将最终路径告诉你。

在狄克斯特拉算法中,你给每段都分配了一个数字或权重,因此狄克斯特拉算法找出的是总权重最小的路径。

在前一章, 你使用了广度优先搜索来查找两点之间的最短路径,那时“最短路径”的意思是段数最少。

重述一下,狄杰斯特拉算法包含4个步骤。

(1) 找出最便宜的节点,即可在最短时间内前往的节点。

(2) 对于该节点的邻居,检查是否有前往它们的更短路径,如果有,就更新其开销。

(3) 重复这个过程,直到对图中的每个节点都这样做了。

(4) 计算最终路径。


术语

狄克斯特拉算法用于每条边都有关联数字的图,这些数字称为权重( weight)。

带权重的图称为加权图( weighted graph),不带权重的图称为非加权图( unweighted graph)。

计算非加权图中的最短路径: 使用广度优先搜索。

计算加权图中的最短路径: 使用狄杰斯特拉算法。

狄杰斯特拉算法只适用于有向无环图( directed acyclic graph, DAG)。


换钢琴例子

有向无环图:

目标:Rama需要确定采用哪种路径将乐谱(起点)换成钢琴(终点)时需要支付的额外费用最少?

动手之前,你需要做些准备工作:创建一个表格,在其中列出每个节点的开销。这里的开销指的是达到节点需要额外支付多少钱。

在执行狄杰斯特拉算法的过程中,你将不断更新这个表。为计算最终路径,还需在这个表中添加表示父节点的列。

开始执行算法:

第一步:找出最便宜的节点。

在这里,换海报最便宜,不需要支付额外的费用。

还有更便宜的换海报的途径吗?这一点非常重要,你一定要想一想。这就是狄杰斯特拉算法背后的关键理念: 找出图中最便宜的节点,并确保没有到该节点的更便宜的路径!

第二步:计算前往该节点的各个邻居的开销。

注意在更新权重的时候,也要更新父节点。

再次执行第一步:下一个最便宜的节点是黑胶唱片——需要额外支付5美元。

再次执行第二步:更新黑胶唱片的各个邻居的开销。

你更新了架子鼓和吉他的开销!这意味着经“黑胶唱片”前往“架子鼓”和“吉他”的开销更低,因此你将这些乐器的父节点改为黑胶唱片。

下一个最便宜的是吉他,因此更新其邻居的开销。

你终于计算出了用吉他换钢琴的开销,于是你将其父节点设置为吉他。最后,对最后一个节点——架子鼓,做同样的处理。

如果用架子鼓换钢琴, Rama需要额外支付的费用更少。因此, 采用最便宜的交换路径时,Rama需要额外支付35美元。

现在来兑现前面的承诺,确定最终的路径。当前,我们知道最短路径的开销为35美元,但如何确定这条路径呢?为此,先找出钢琴的父节点。

钢琴的父节点为架子鼓,这意味着Rama需要用架子鼓来换钢琴。因此你就沿着这一边。

架子鼓的父节点为黑胶唱片。

因此Rama需要用黑胶唱片了换架子鼓。显然,他需要用乐谱来换黑胶唱片。通过沿父节点回溯,便得到了完整的交换路径。

下面是Rama需要做的一系列交换。

最短路径的概念:

最短路径指的并不一定是物理距离,也可能是让某种度量指标最小。在这个示例中,最短路径指的是Rama想要额外支付的费用最少。这都要归功于狄杰斯特拉算法。

注意: 如果有负权边,就不能使用狄杰斯特拉算法。因为负权边会导致这种算法不管用。

这是因为狄杰斯特拉算法这样假设:对于处理过的海报节点,没有前往该节点的更短路径。这种假设仅在没有负权边时才成立。因此, 不能将狄杰斯特拉算法用于包含负权边的图。在包含负权边的图中,要找出最短路径,可使用另一种算法——贝尔曼-福德算法( Bellman-Ford algorithm)。本书不介绍这种算法,你可以在网上找到其详尽的说明。


代码实现

以下面的有向无环图为例:

需要三个散列表:

随着算法的进行,你将不断更新散列表costs和parents。

这里需要同时存储邻居和前往邻居的开销。例如,起点有两个邻居——A和B。

graph = {}
graph["start"] = {}
graph["start"]["a"] = 6
graph["start"]["b"] = 2

因此graph["start"]是一个散列表。要获取起点的所有邻居,可像下面这样做。

>>> print graph["start"].keys()
["a", "b"]
>>> print graph["start"]["a"]
2
>>> print graph["start"]["b"]
6

每一个节点都是一个字典,这个字典里面存储了它的邻居和权重;邻居就是字典的keys,权重是字典的values。

表示节点b也是一个字典,graph["b"]["a"]=3,表示从b点到a点,权重为3。

下面来添加其他节点及其邻居。

graph["a"] = {}
graph["a"]["fin"] = 1
graph["b"] = {}
graph["b"]["a"] = 3
graph["b"]["fin"] = 5
graph["fin"] = {} #终点没有任何邻居

接下来, 需要用一个散列表来存储每个节点的开销。节点的开销指的是从起点出发前往该节点需要多长时间。

在Python中能够表示无穷大吗?你可以这样做:

infinity = float("inf")

创建开销表的代码如下:

infinity = float("inf")
costs = {}
costs["a"] = 6
costs["b"] = 2
costs["fin"] = infinity

还需要一个存储父节点的散列表:

创建这个散列表的代码如下:

parents = {}
parents["a"] = "start"
parents["b"] = "start"
parents["fin"] = None

最后,你需要一个数组,用于记录处理过的节点,因为对于同一个节点,你不用处理多次。

processed = []

准备工作做好了,下面来看看算法。

node = find_lowest_cost_node(costs)#在未处理的节点中找出开销最小的节点
while node is not None:#这个while循环在所有节点都被处理过后结束cost = costs[node]neighbors = graph[node]for n in neighbors.keys(): #遍历当前节点的所有邻居new_cost = cost + neighbors[n]if costs[n] > new_cost: #如果经当前节点前往该邻居更近,costs[n] = new_cost #就更新该邻居的开销parents[n] = node #同时将该邻居的父节点设置为当前节点processed.append(node) #将当前节点标记为处理过node = find_lowest_cost_node(costs)#找出接下来要处理的节点,并循环def find_lowest_cost_node(costs):lowest_cost = float("inf") #初始设定lowest_cost是无穷大lowest_cost_node = Nonefor node in costs:#遍历所有的节点cost = costs[node] #获取当前节点的cost值if cost < lowest_cost and node not in processed: #如果当前节点的开销更低且未处理过,lowest_cost = cost#就将其视为开销最低的节点lowest_cost_node = nodereturn lowest_cost_node

对于下图,找出开销最低的节点。

获取该节点的开销和邻居。

遍历邻居。

每个节点都有开销。开销指的是从起点前往该节点需要多长时间

在这里,你计算从起点出发,经节点B前往节点A(而不是直接前往节点A)需要多长时间。

接下来对新旧开销进行比较。

找到了一条前往节点A的更短路径!因此更新节点A的开销:

这条新路径经由节点B,因此节点A的父节点改为节点B。

现在回到了for循环开头。B的下一个邻居是终点节点:

经节点B前往终点需要多长时间呢?

需要7分钟。终点原来的开销为无穷大,比7分钟长:

设置终点节点的开销和父节点。

你更新了节点B的所有邻居的开销。现在,将节点B标记为处理过。

找出接下来要处理的节点

获取节点A的开销和邻居。

节点A只有一个邻居:终点节点。

当前,前往终点需要7分钟。如果经节点A前往终点,需要多长时间呢?

neighbors[节点n]用于获取当前节点node到节点n的距离(权重)。

经节点A前往终点所需的时间更短!因此更新终点的开销和父节点。

处理所有的节点后,这个算法就结束了。


小结

 广度优先搜索用于在非加权图中查找最短路径。

 狄杰斯特拉算法用于在加权图中查找最短路径。

 仅当权重为正时狄杰斯特拉算法才管用。

 如果图中包含负权边,请使用贝尔曼-福德算法。

迪杰斯特拉算法c++_《算法图解》学习记录7--迪杰斯特拉算法相关推荐

  1. 全息图像学习记录(1)——SFFT算法

    全息图像学习记录(1)--SFFT算法 (第一次写作) 编程环境 具体代码 小结 (第一次写作) 最近开始搞全息图的模拟,现在以这种方式记录下来.在光学里,菲涅耳衍射(Fresnel diffract ...

  2. dijkstra最短路径算法视频_单源最短路径(1):Dijkstra 算法

    一:背景 Dijkstra 算法(中文名:迪杰斯特拉算法)是由荷兰计算机科学家 Edsger Wybe Dijkstra 提出.该算法常用于路由算法或者作为其他图算法的一个子模块.举例来说,如果图中的 ...

  3. 【学习 记录】狄克斯特拉算法 - Java

    最近学习<算法图解>一书时,看到狄克斯特拉算法之前没有使用过,在学习后用常用语言Java将算法实现出来以加深印象. 作用 狄克斯特拉算法用于找出最快的路径,而常用的广度优先搜索算法可用于找 ...

  4. vrp 节约算法 c++_滴滴技术:浅谈滴滴派单算法

    作者: 王犇 刘春阳 徐哲 来自:滴滴技术 导读:说到滴滴的派单算法,大家可能感觉到既神秘又好奇,从出租车扬召到司机在滴滴平台抢单最后到平台派单,大家今天的出行体验已经发生了翻天覆地的变化,面对着每天 ...

  5. rssi室内定位算法原理_室内定位方案常用的4种定位算法

    目前常见的室内定位技术有超宽带UWB室内定位技术,蓝牙室内定位技术,RFID(无线射频识别)定位,超声波定位,Wi-Fi定位等.室内定位依赖于定位算法,定位算法决定了室内定位的模式.室内定位种类虽然比 ...

  6. 三维图形几何变换算法实验_基于深度学习的三维重建算法综述

    点击上方"计算机视觉life",选择"星标" 快速获得最新干货 00 前言 目前,三维重建技术已在游戏.电影.测绘.定位.导航.自动驾驶.VR/AR.工业制造以 ...

  7. 2023.2.3,周五【图神经网络 学习记录17】二部图——BiNE算法:显式关系,隐式关系;新的随机游走方式 特点:随机游走次数 是跟节点中心性相关的,在随机游走的过程中 添加一个停止随机游走的概率

    声明:仅学习使用~ 前情提要: 2023.2.2,周四[图神经网络 学习记录16]异构图Graph Embedding算法--GATNE(异构图多属性 多边 类型算法),不建议普通PC跑-PyChar ...

  8. 学习记录 --用CUDA完成泛洪算法

    算法思路 传统的泛红算法主要有两种方法,递归或者队列扫描,这两种方法在总体思路大致都是从种子点开始,逐步扫描周围的符合要求的点(比如和种子点颜色距离小于一个规定的值),当出现符合要求的点后将此点染色, ...

  9. 学大数据要学哪些算法_大数据学习之不得不知的八大算法

    算法一:快速排序法 快速排序是由东尼 · 霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n) 次比较.在最坏状况下则需要Ο(n2) 次比较,但这种状况并不常见. 事实上,快 ...

  10. fifo算法模拟_我是怎样学习算法的?(V1.0)

    我相信很多人都是因为找工作才去看数据结构与算法,我自己也是出于这个目的.我自己在学习数据结构和算法上走了很多弯路,原因就是没有系统地的去学习.看了很多书,刷了很多题,浪费了不少时间,所以希望看到这篇文 ...

最新文章

  1. 域名年龄-SEO搜索引擎优化
  2. AI学习笔记之——如何理解机器学习(Machine Learning)
  3. 人机语言(MML: Man-Machine Language)
  4. 3D芯片大脑:在芯片上培养脑细胞,还能用来测试新药
  5. android银行卡匹配、详情展开动画、仿爱奇艺视频拖拽、扫码识别手机号等源码...
  6. android 手机号分段_android 手机号分段_android系统实现手机号添加分割符
  7. Juqery让世界更美好--超级简单实用的(上、下)自动翻的最佳效果,有图为证!...
  8. 苹果APPLE最新MI芯片笔记本安装第三方内核扩展
  9. IOS开发基础之使用AFNetworking框架下载服务器资源图片
  10. 学会用taro封装一个组件
  11. 应理解计算机专业的学科特点,职业高中计算机专业测验试题编写的策略初探.doc...
  12. p沟道大电流mos管贴片_一文读懂MOS管工作原理
  13. poj4474 Scout YYF I(概率dp+矩阵快速幂)
  14. 从一个插座面板开始说故事
  15. 如何把psd格式转为html,将psd转化为HTML网页详情讲解
  16. Flutter--使用相机
  17. 屏幕刷新频率怎么更改?
  18. cheng@ARM结构与编程之day3-MOV LSL
  19. html中加粗的字体如何改细,css font-weight 属性设置文本字体的粗细
  20. Shell中declare -A的用法?

热门文章

  1. Learn OpenGL (八):颜色
  2. vue 编写H5页面在公众号外部获取手机本地坐标经纬度
  3. 关于使用python logging模块的几点总结
  4. Unity 2021人工智能导论 Introduction to Artificial Intelligence in Unity 2021
  5. 在Blender中创建真实的汽车CGI视觉动画效果
  6. ARM 的几个重要特点
  7. Visual Studio 2005 Team System下载地址
  8. Data - 数据思维 - 中篇
  9. pip install失败报错解决方案
  10. Django ORM操作