探究最短路问题:Dijkstra算法

开发 前端 算法
最短路问题最短路问题(Shortest Path Problems):给定一个网络,网络的边上有权重,找一条从给定起点到给定终点的路径使路径上的边权重总和最小。

[[386543]]

 在上次写道关于数据结构的图,图的算法的考点只有一个:最短路问题。

最短路问题

最短路问题(Shortest Path Problems):给定一个网络,网络的边上有权重,找一条从给定起点到给定终点的路径使路径上的边权重总和最小。


比如上图的:图中点1到点4的最短路径长度应为3(从1到2到4)。

最短路问题常用Dijkstra算法解决

Dijkstra算法

Dijkstra算法是典型的单源最短路径算法,用于计算一个节点到其他所有节点的最短路径。主要特点是以起始点为中心向外层层扩展,直到扩展到终点为止。

比如,上图Dijkstra算法就是不断地寻找开始节点到邻居节点的所有的路径,将最初的距离设置为最短距离,然后不断的更新节邻居节点的最短距离,直到最远的节点的最短距离求解出来的过程。

文字描述不清楚,看下面的动图。

图片

将图上的顶点分为已访问visited和未访问node两个集合。

每次从visited向外拓展一个点,拓展规则是在可更新的点里是距离最小的。

我们还是以上面的图为例


先用邻接矩阵表示无向图:

  1. MAX = 9999 
  2.  
  3. g= [ 
  4.     [0, 1, 4, 6], 
  5.     [MAX, 0, MAX, 2], 
  6.     [MAXMAX, 0, 1], 
  7.     [MAXMAXMAX, 0] 

邻接矩阵g[0][1]=1表示,第一个节点到第二个节点的距离是1。

目的是要求出开始点1到其他各个点的最小路径距离

  1. n = 4 #4个点 
  2. # 初始化 visited  
  3. visitd = [0] * (n) #记录该点是否为访问过 
  4. # 第一个点已经访问了 
  5. visitd[0] = 1 
  6. #初始化源点到各个点的距离 node 集合 
  7. d = g[0] 
  8.  
  9. for i in range(2, n): 
  10.     # 遍历d 取出权重最小节点的位置 
  11.     minWeigth = MAX 
  12.     for j in range(2, n): 
  13.         if d[j] < minWeigth and visitd[j] == 0: 
  14.             minWeigth = d[j] 
  15.             k = j 
  16.             # 表示k是当前距1最短的点,同时标记k已经被找过 
  17.     visitd[k] = 1 
  18.     #  用该点进行松弛(relax) 
  19.     for j in range(2, n): 
  20.         if d[j] > d[k] + g[k][j] and visitd[j] == 0: 
  21.             d[j] = d[k] + g[k][j] 
  22.  
  23. for i in range(1,n): 
  24.     print(d[i]) 
  25.      

至此,得到节点1到其余三个节点的最短距离是1、4和5。

「把Dijkstra 算法应用于无权图,或者所有边的权都相等的图,Dijkstra 算法等同于BFS搜索。」

多点求解

在很多的时候,要求输入一组点,然后求出输入一个起始点,得到无向图最短路径。

  1. import math 
  2. # 假设图中的顶点数 
  3. V = 6 
  4. # 标记数组:used[v]值为False说明改顶点还没有访问过,在S中,否则在U中! 
  5. used = [False for _ in range(V)] 
  6. # 距离数组:distance[i]表示从源点s到i的最短距离,distance[s]=0 
  7. distance = [float('inf'for _ in range(V)] 
  8. # cost[u][v]表示边e=(u,v)的权值,不存在时设为INF 
  9. # cost领接表 
  10. cost = [[float('inf'for _ in range(V)] for _ in range(V)] 
  11.  
  12. def dijkstra(s): 
  13.     distance[s] = 0 
  14.     while True
  15.         # v在这里相当于是一个哨兵,对包含起点s做统一处理! 
  16.         v = -1 
  17.         # 从未使用过的顶点中选择一个距离最小的顶点 
  18.         for u in range(V): 
  19.             if not used[u] and (v == -1 or distance[u] < distance[v]): 
  20.                 v = u 
  21.         if v == -1: 
  22.             # 说明所有顶点都维护到S中了! 
  23.             break 
  24.         # 将选定的顶点加入到S中, 同时进行距离更新 
  25.         used[v] = True 
  26.         # 更新U中各个顶点到起点s的距离。之所以更新U中顶点的距离,是由于上一步中确定了k是求出最短路径的顶点,从而可以利用k来更新其它顶点的距离;例如,(s,v)的距离可能大于(s,k)+(k,v)的距离。 
  27.         for u in range(V): 
  28.             distance[u] = min(distance[u], distance[v] + cost[v][u]) 
  29.  
  30.  
  31. for _ in range(9): 
  32.     v, u, w = list(map(int, input().split())) 
  33.     cost[v][u] = w 
  34.     cost[u][v] = w 
  35. s = int(input('请输入一个起始点:')) 
  36. dijkstra(s) 
  37. print(distance) 

测试用例

  1. 0 1 1 
  2. 0 2 2 
  3. 0 3 3 
  4. 1 4 7 
  5. 1 5 9 
  6. 2 4 4 
  7. 3 4 5 
  8. 3 5 6 
  9. 4 5 8 
  10. 请输入一个起始点:0 
  11. [0, 1, 2, 3, 6, 9] 

在测试用例中的0 1 1表示第一个顶点到第二个顶点的距离是1。

Dijkstra算法使用邻接表的时间复杂度是。因此,很多使用堆进行优化或者使用散列表对多余的空间进行优化。

 

责任编辑:姜华 来源: Python之王
相关推荐

2011-05-17 13:58:37

最短路径

2011-05-17 14:29:29

Dijkstra

2011-05-17 14:11:06

Dijkstra

2013-04-23 09:31:52

SQL Server

2013-06-24 09:37:34

OSPF协议SPF算法路由技术

2014-03-26 09:04:42

算法Floyd最短算法

2011-12-19 12:39:37

Java

2021-05-10 08:07:40

图算法路径顶点

2015-07-16 14:25:56

SDN网络感知服务

2024-04-02 11:37:59

AGI网络模型GAN

2022-11-28 10:14:16

研究算法

2021-08-26 17:36:42

Floyd算法数据结构

2021-08-09 06:57:44

最短路传入函数

2020-04-22 11:19:07

贪心算法动态规划

2011-06-01 09:27:00

OSPF路由路由器

2013-12-23 09:25:21

2015-12-07 17:07:36

SDN网络流量

2023-10-25 09:00:00

算法Dijkstra算法

2021-09-08 10:32:29

微服务容器化Serverless

2009-11-12 14:32:00

BGP路由协议
点赞
收藏

51CTO技术栈公众号