最短路径之Dijkstra算法和Floyd-Warshall算法
2017-07-26 08:11
483 查看
最短路径算法
最短路径算法通常用在寻找图中任意两个结点之间的最短路径或者是求全局最短路径,像是包括Dijkstra、A*、Bellman-Ford、SPFA(Bellman-Ford的改进版本)、Floyd-Warshall、Johnson、BFS等等,这里要集中介绍Dijkstra和
Floyd,前者用来处理任意两个结点之间的最短路径,后者处理图中所有的最短路径。
Dijkstra算法
理解
其思想为,我们首先纪录下每个点到原点的距离,这个距离会在每一轮遍历的过程中刷新。每一个结点到原点的最短路径是其前驱结点到原点的最短路径加上前驱结点到当前结点的路径和。我们以下面这幅图片为例,假定起始结点为1,求该结点到其余各个结点的最短路径。
执行步骤为:
步骤 | 描述 | 前驱结点 |
---|---|---|
1 | 将当前结点到其它结点的路径都初始化为无穷大 | 无 |
2 | 依次计算每个结点的路径长度,此时可以获得结点1到其它的结点2、3、4、5、6的路径长度为[7, 9, ∞,∞,14]`,取其中最小的值7,结点2作为前驱结点 | 无 |
3 | 此时通过结点2可以到达结点4和5,并且其路径等于起始结点到前驱结点的路径加上前驱结点到目标结点的路径长度,因此此时结点1到其它结点3、4、5、6的路径长度为[17, 22, ∞, ∞],此时将现在的路径长度和之前的路径长度进行比较,取对应的较小值,得到最短距离[9, 22, ∞, 14],取其最小值9,结点3更新成前驱结点 | 2 |
4 | 同样的道理,此时结点1到其它的结点4、5、6的路径长度为[20, ∞, 11],和之前的路径长度进行比较,得到最短距离[20, ∞, 11],取最小值11,结点6作为前驱结点 | 3 |
5 | 同样的道理,得到结点1到其它的结点4, 5的路径长度为[20, 20],和之前对比,最短距离更新成[20,20] | 6 |
6 | 因为此时剩下了两个相等路径长度的结点,取任意一个结点,结果都是一样的,所以取哪个都可以 |
function Dijkstra(G, w, s) for each vertex v in V[G] # 初始化 d[v] := infinity # 將各點的已知最短距離先設成無窮大 previous[v] := undefined # 各点的已知最短路径上的前趋都未知 d[s] := 0 # 因为出发点到出发点间不需移动任何距离,所以可以直接将s到s的最小距离设为0 S := empty set Q := set of all vertices while Q is not an empty set # Dijkstra演算法主體 u := Extract_Min(Q) S.append(u) for each edge outgoing from u as (u,v) if d[v] > d[u] + w(u,v) # 拓展边(u,v)。w(u,v)为从u到v的路径长度。 d[v] := d[u] + w(u,v) # 更新路径长度到更小的那个和值。 previous[v] := u # 紀錄前趨頂點其中的Extract_Min为提取最小值。
实现
import sys class Graph(): def __init__(self, vertices): self.V = vertices self.graph = [[0 for _ in range(self.V)] for _ in range(self.V)] # 打印距离 def print_distance(self, dist, parent): for node in range(self.V): print('distance') print(node, dist[node]) print('path') self.print_path(parent, node) print('---------') # 打印路径 def print_path(self, parent, j): if parent[j] == -1: print(j) return self.print_path(parent, parent[j]) print(j) # 找出最小距离的结点 def min_distance(self, dist, sptSet): min_val = sys.maxsize min_index = 0 for v in range(self.V): if dist[v] < min_val and not sptSet[v]: min_val = dist[v] min_index = v return min_index # 核心算法 def dijkstra(self, src): dist = [sys.maxsize] * self.V dist[src] = 0 sptSet = [False] * self.V parent = [-1] * self.V for count in range(self.V): # 找出前驱结点 u = self.min_distance(dist, sptSet) sptSet[u] = True # 如果某个节点的路径大于经过前驱结点的路径,则更新结果成经过前驱结点的路径 for v in range(self.V): if self.graph[u][v] > 0 and not sptSet[v] and dist[v] > dist[u] + self.graph[u][v]: dist[v] = dist[u] + self.graph[u][v] parent[v] = u self.print_distance(dist, parent) g = Graph(8) g.graph = [[0, 0, 7, 7, 2, 0, 0, 0], [0, 0, 3, 8, 0, 0, 8, 0], [7, 3, 0, 0, 0, 7, 0, 0], [7, 8, 0, 0, 0, 0, 0, 0], [2, 0, 0, 0, 0, 0, 0, 8], [0, 0, 7, 0, 0, 0, 8, 0], [0, 8, 0, 0, 0, 8, 0, 6], [0, 0, 0, 0, 8, 0, 6, 0]] g.dijkstra(0)
Floyd
理解
其原理为:假定存在某个结点k在结点i和结点j之间,如果i和j之间的路径长度大于经过k到,则将其距离更新成经过结点k的路径长度。因此在实现中使用三个循环即可,但是要注意循环的顺序,最外层是结点k的遍历,这样可以避免i和j的遍历过早的把最短路径给定下来。结果为:
实现
import copy INF = 1e9 class Graph(): def __init__(self, graph): self.V = len(graph) self.graph = graph # 打印距离 def print_distance(self, dist): for i in range(self.V): for j in range(self.V): print('%5s' % (dist[i][j] if dist[i][j] != INF else 'INF'), end='') print('') # 核心算法 def floydwarshall(self): dist = copy.deepcopy(self.graph) for k in range(self.V): for i in range(self.V): for j in range(self.V): # 不考虑自己指向自己的情况 if i == j: continue dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]) self.print_distance(dist) g = Graph([[INF, INF, 1, INF, INF, INF, INF, INF], [INF, INF, 2, 8, INF, 5, INF, INF], [9, INF, INF, INF, 2, INF, INF, INF], [INF, INF, INF, INF, INF, 2, INF, INF], [INF, INF, INF, INF, INF, INF, INF, 9], [INF, INF, INF, INF, INF, INF, INF, INF], [INF, INF, INF, INF, 1, INF, INF, INF], [INF, INF, INF, INF, INF, 7, 7, INF]]) g.floydwarshall()
相关文章推荐
- 【最短路径】:Dijkstra算法、SPFA算法、Bellman-Ford算法和Floyd-Warshall算法
- 最短路径之Dijkstra算法和Floyd-Warshall算法
- 最短路径算法(Dijkstra算法、Floyd-Warshall算法)
- 最短路径的Floyd与Dijkstra算法
- 最简单的最短路径算法 - Floyd_Warshall算法
- Floyd-Warshall算法---求解任意两节点的最短路径
- 求图中最短路径算法之Floyd-Warshall算法——C++实现
- 任意两点之间的最短路径问题(Floyd-Warshall算法)
- 所有节点对最短路径-Floyd-Warshall算法
- Floyd-Warshall算法求任意两点间最短路径
- 所有结点对最短路径问题(Floyd-Warshall算法)——算法导论学习笔记(1)
- 【动态规划】每对顶点之间的最短路径之Floyd-Warshall算法
- Floyd-Warshall算法求解所有结点对的最短路径问题Java实现
- Floyd-Warshall算法:求结点对的最短路径问题
- Floyd-Warshall算法:求结点对的最短路径问题
- 任意两点间的最短路径---floyd_warshall算法
- Floyd-Warshall算法:求结点对的最短路径问题
- [算法]获得最短路径的Floyd与Dijkstra算法
- 关于Floyd-Warshall算法由前趋矩阵计算出的最短路径反映出了算法的执行过程特性的证明
- 多源最短路径---Floyd-Warshall算法