K Shortest Paths算法之Yen algorithm

Yen’s算法是一种在图论中用于计算单源K最短无环路径的算法,该算法由Jin Y. Yen在1971年提出。这个算法的时间复杂度和空间复杂度都取决于用于计算偏离路径的最短路径算法。如果使用Dijkstra算法,那么时间复杂度为O(KN3),采用Fibonacci堆计算可以优化到O(KN(M+NlogN))。

Yen algorithm的关键步骤

1.确定第一条最短路径:使用任何有效的最短路径算法(例如Dijkstra算法)从源点到汇点计算最短路径,将其作为第一条最短路径。

2.确定所有其他K最短路径:假设已经找到了从源点到汇点的所有路径,然后进行迭代,每次迭代都会找到所有的偏离路径,并选择一条最小长度的路径成为下一条最短路径。在这个迭代过程中,需要进行以下操作:

  • 选择根路径:找到在前一条最短路径中的子路径,该子路径跟随前i个节点,其中i从1到k-1。
  • 找到偏离路径:计算从偏离节点(即根路径的最后一个节点)到汇点的最短路径,这就是偏离路径。
  • 将根路径和偏离路径加入到候选路径集合中:将根路径和偏离路径相加,形成一条完整的路径,然后将这条路径加入到候选路径集合中。

3.选择下一条最短路径:从候选路径集合中找到成本最低的路径,将其从候选路径集合中移除,并将其加入到最短路径集合中,然后继续下一次迭代。

4.重复步骤2和3,直到找到K条最短路径。

Yen algorithm图例

1.使用Dijkstra算法等,确定第一条最短路径A1=13,放入容器A,路径A1上的节点分别记为1,2,3,4
在这里插入图片描述
2.确定所有其他K最短路径
偏离节点为1时,选择节点1和2之间的链路weight变为无穷,R为根路径,S为偏离路径,计算出绿色的路径A2=14,先放入候选容器B
在这里插入图片描述
偏离节点为2时,选择节点2和3之间的链路weight变为无穷,计算出红色的路径A2=17,放入候选容器B
在这里插入图片描述
偏离节点为3时,选择节点3和4之间的链路weight变为无穷,计算出紫色的路径A2=16,放入候选容器B
在这里插入图片描述
所有当K=2时,计算出的A1和A2路径就如下,如果K>2时,那还要A2再单独拿出来,重复上面几步的运算
在这里插入图片描述

参考网站

Yen, Jin Y. (1970). “An algorithm for finding shortest routes from all source nodes to a given destination in general networks”. Quarterly of Applied Mathematics. 27 (4): 526–530. doi:10.1090/qam/253822. MR 0253822.

https://www.ams.org/journals/qam/1970-27-04/S0033-569X-1970-0253822-7/

https://en.wikipedia.org/wiki/Yen%27s_algorithm

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是基于 Dijkstra 算法Yen 算法求 k 短路的 Python 代码实现: ```python from queue import PriorityQueue from collections import defaultdict def dijkstra(graph, start, end=None): # 初始化距离和前驱节点 distance = {start: 0} predecessor = {start: None} # 初始化优先队列,按距离排序 pq = PriorityQueue() pq.put((0, start)) while not pq.empty(): # 取出距离最小的节点 curr_dist, curr_node = pq.get() # 如果已经到达终点,则返回到达终点的距离和路径 if end is not None and curr_node == end: path = [] while curr_node is not None: path.append(curr_node) curr_node = predecessor[curr_node] path.reverse() return curr_dist, path # 遍历当前节点的所有邻居节点 for neighbor, weight in graph[curr_node].items(): # 计算到邻居节点的距离 new_dist = curr_dist + weight # 更新邻居节点的距离和前驱节点 if neighbor not in distance or new_dist < distance[neighbor]: distance[neighbor] = new_dist predecessor[neighbor] = curr_node pq.put((new_dist, neighbor)) # 如果没有到达终点,则返回起点到所有节点的距离和前驱节点 return distance, predecessor def yen_k_shortest_paths(graph, start, end, k): # 初始化最短路径和备选路径 A = [(None, [start])] B = PriorityQueue() for k in range(1, k+1): # 遍历备选路径 for i in range(len(A[-1][1])-1): # 切断备选路径中的边 spur_node = A[-1][1][i] root_path = A[-1][1][:i+1] # 构建新的图 subgraph = defaultdict(dict) for path_dist, path in A: if root_path == path[:i+1]: src = path[i] dst = path[i+1] subgraph[src][dst] = graph[src][dst] for node in root_path: if node != spur_node: # 移除所有与 spur_node 相邻的节点 for neighbor in subgraph[spur_node]: del subgraph[neighbor][spur_node] del subgraph[spur_node] # 执行 Dijkstra 算法,计算 spur_node 到所有节点的最短路径 spur_path_dist, spur_path = dijkstra(subgraph, spur_node, end) if spur_path is not None: # 将 spur_path 和 root_path 合并成一条路径 total_path = root_path[:-1] + spur_path # 计算总距离 total_dist = 0 for j in range(len(total_path)-1): total_dist += graph[total_path[j]][total_path[j+1]] # 将新路径加入备选路径 B.put((total_dist, total_path)) # 如果没有更多备选路径,则退出循环 if B.empty(): break # 如果没有更多备选路径,则退出循环 if B.empty(): break # 选择距离最短的路径作为最新的最短路径 shortest_dist, shortest_path = B.get() A.append((shortest_dist, shortest_path)) # 返回前 k 条最短路径 return [path for dist, path in A[:k]] ``` 其中,`graph` 是一个字典,表示图中的邻接矩阵。例如,`graph[src][dst]` 表示从 `src` 到 `dst` 的边权重。`start` 和 `end` 分别表示起点和终点。`k` 表示求前 k 条最短路径。函数 `yen_k_shortest_paths` 返回前 k 条最短路径的列表,每个路径都是一个节点列表。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姜亚轲

你花钱的样子真帅

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值