YEN算法实战:用Python实现K短路求解(附完整代码与测试用例)
YEN算法实战:用Python实现K短路求解(附完整代码与测试用例)
如果你曾经在规划物流路线、设计通信网络或者分析社交网络影响力路径时,遇到过“除了最优解,还有什么其他不错的备选方案?”这样的问题,那么K短路算法很可能就是你工具箱里缺失的那块拼图。我们太习惯于寻找那条最短、最快、最省的“唯一”路径,但在真实世界里,最优路径可能因为突发拥堵、资源占用或成本波动而瞬间失效。这时,拥有一个按优劣排序的“路径备选库”就显得至关重要。YEN算法,作为求解K短路问题的经典方法,以其清晰易懂的“偏离路径”思想,成为了许多工程师解决此类问题的首选。今天,我们不谈复杂的数学证明,而是直接切入工程实现,用Python手把手带你构建一个健壮、高效的K短路求解器,并附上能直接跑起来的代码和贴近实际的测试用例。
1. 理解核心:YEN算法到底在做什么?
简单来说,给定一个起点、一个终点和一个数字K,YEN算法的目标是找出从起点到终点的第1短、第2短、第K短的路径。这里的“短”指的是路径的总权重最小。它巧妙的核心思想是“有序生成”和“可控偏离”。
想象一下,你已经找到了从家到公司的前几条最快路线。YEN算法寻找下一条新路线的策略是:在前一条已知路线的基础上,选择一个点进行“偏离”。具体来说,它会依次审视当前最短路径上的每一个节点(除了终点),然后尝试在这个节点上“拐个弯”,走一条之前没走过的边,之后再以最快的方式奔向终点。这个“拐弯”后接上“最快奔向终点”的整段新路线,就是一条候选的新路径。
这里有两个关键约束保证了算法的正确性和效率:
- 偏离后的新路段(称为偏离路径)不能包含前半段已经走过的节点,这避免了绕圈子形成环路。
- 在计算偏离点到终点的最短路径时,需要暂时“屏蔽”掉某些边,以确保生成的是真正的新路径,而不是旧路径的简单变体。
为了管理这些路径,算法维护两个列表:
- A列表:已经确认的前K短路径,按长度排序。
- B列表:候选路径池,存放由当前A列表中最后一条路径生成的所有可能偏离路径。
每一轮迭代,算法从B列表中挑选出总长度最短的那条路径,晋升到A列表,然后以这条新晋升的路径为基础,开始下一轮的偏离路径生成。如此循环,直到我们收集齐K条路径。
注意:YEN算法求解的是“无环”K短路,即路径中不允许节点重复出现。这对于大多数实际场景(如车辆路径规划、数据包路由)是更符合需求的。
2. 工程基石:构建我们的图与最短路径引擎
在动手实现YEN算法之前,我们需要先打造两个可靠的基础组件:一个灵活的图数据结构和一台高效的最短路径“发动机”。
2.1 设计图数据结构
我们选择邻接表来存储图,因为它对于稀疏图(边数远小于顶点数的平方)的空间利用率更高,而现实中的网络大多如此。这里我们用Python的字典和列表来实现一个简洁的类。
from typing import Dict, List, Tuple, Optional
import heapq
class Graph:
"""带权重的有向图(无向图可用两条有向边表示)"""
def __init__(self):
# 邻接表:self.adj[起点] = [(终点, 权重), ...]
self.adj: Dict[str, List[Tuple[str, float]]] = {}
self.vertices = set()
def add_edge(self, u: str, v: str, weight: float, directed: bool = False):
"""添加一条边。如果 directed=False,则添加双向边。"""
self.vertices.update([u, v])
if u not in self.adj:
self.adj[u] = []
self.adj[u].append((v, weight))
if not directed:
if v not in self.adj:
self.adj[v] = []
self.adj[v].append((u, weight))
def get_neighbors(self, node: str) -> List[Tuple[str, float]]:
"""获取节点的所有出边邻居及权重"""
return self.adj.get(node, [])
这个Graph类足够轻量,add_edge方法可以方便地构建有向图或无向图。get_neighbors方法则为后续的最短路径算法提供了便利的接口。
2.2 实现Dijkstra最短路径算法
YEN算法在每一步生成偏离路径时,都需要计算从一个“偏离点”到终点的最短路径。Dijkstra算法是解决非负权重图单源最短路径问题的标准答案。我们将实现一个增强版的Dijkstra,使其能够排除特定节点——这是YEN算法中实现“路径节点不重复”约束的关键。
def dijkstra(
graph: Graph,
start: str,
target: str,
excluded_nodes: Optional[List[str]] = None
) -> Tuple[float, List[str]]:
"""
使用Dijkstra算法求最短路径。
返回: (最短距离, 路径节点列表[从起点到终点])
如果不可达,返回 (float('inf'), [])
"""
if excluded_nodes is None:
excluded_nodes = []
# 如果起点或终点被排除,直接返回不可达
if start in excluded_nodes or target in excluded_nodes:
return float('inf'), []
# 初始化
dist = {v: float('inf') for v in graph.vertices}
prev = {v: None for v in graph.vertices}
dist[start] = 0
# 优先队列 (距离, 节点)
pq = [(0, start)]
while pq:
current_dist, u = heapq.heappop(pq)
# 如果找到终点,可以提前终止(Dijkstra特性)
if u == target:
break
# 如果当前距离大于已知最短距离,跳过
if current_dist > dist[u]:
continue
# 遍历邻居
for v, weight in graph.get_neighbors(u):
if v in excluded_nodes: # 跳过被排除的节点
continue
new_dist = current_dist + weight
if new_dist < dist[v]:
dist[v] = new_dist
prev[v] = u
heapq.heappush(pq, (new_dist, v))
# 回溯构建路径
if dist[target] == float('inf'):
return float('inf'), []
path = []
node = target
while node is not None:
path.append(node)
node = prev[node]
path.reverse() # 从起点到终点
return dist[target], path
这个dijkstra函数有三个亮点:
- 支持节点排除:通过
excluded_nodes参数,我们可以禁止路径经过某些节点,这是实现YEN算法中“偏离路径不与根路径共享节点”的核心。 - 使用优先队列:
heapq模块实现了最小堆,使得算法的时间复杂度为O((V+E) log V),非常高效。 - 提前终止:当目标节点从优先队列中弹出时,其距离已是最短,可以立即结束搜索,节省计算。
有了这两个坚实的轮子,我们就可以开始组装YEN算法这辆赛车了。
3. 核心实现:一步步构建YEN算法
现在,让我们进入最激动人心的部分:用Python实现YEN算法。我们将遵循算法的经典步骤,并特别注意工程上的细节处理,比如去重、边界条件和性能。
3.1 算法主框架与数据结构设计
首先,我们需要定义路径的表示方式。我们将一条路径定义为一个元组:(总距离, 节点列表)。同时,我们需要两个列表来管理路径。
def yen_ksp(
graph: Graph,
source: str,
target: str,
K: int
) -> List[Tuple[float, List[str]]]:
"""
YEN算法求解K短路。
返回: 一个列表,包含从第1短到第K短的路径(距离,节点列表)。
如果实际找到的路径数少于K,则返回所有能找到的路径。
"""
# A: 已确定的K短路径列表
A: List[Tuple[float, List[str]]] = []
# B: 候选路径的最小堆 (距离, 路径, 用于去重的标识)
B = [] # 元素为 (距离, 路径节点列表)
# 第1步:计算最短路径(A1)
dist, path = dijkstra(graph, source, target)
if not path: # 如果起点终点不连通
return A
A.append((dist, path))
for k in range(1, K):
# 第2步:获取上一条最短路径(A_{k-1})用于生成候选
prev_dist, prev_path = A[-1]
# 对前一条路径上的每个偏离点(除了终点)进行操作
for i in range(len(prev_path) - 1):
# 根路径:从起点到偏离点 prev_path[i]
spur_node = prev_path[i]
root_path = prev_path[:i+1]
root_dist = 0
# 计算根路径的距离(也可以在选择偏离点时动态计算,这里预计算)
for j in range(len(root_path)-1):
# 在实际代码中,我们需要从图中查询边权重,这里用简化逻辑
# 我们会在后续的‘generate_candidate’函数中详细计算
pass
# 关键:临时修改图,防止走回头路
# 1. 移除根路径最后一条边(防止直接走回原路径)
# 2. 移除所有A中路径在偏离点之后与根路径相同的边
# 这些操作在Dijkstra中通过‘排除节点’和‘排除边’来实现
# 我们将这部分逻辑封装
candidate = _generate_candidate(graph, source, target, spur_node, root_path, A)
if candidate:
heapq.heappush(B, candidate)
# 第3步:从候选堆B中选出最短的路径加入A
if not B:
break # 没有更多候选路径了
next_path = heapq.heappop(B)
A.append(next_path)
return A
上面的代码勾勒出了算法的主循环。其中,最复杂也最关键的部分是_generate_candidate函数,它负责在给定的偏离点上,生成一条新的候选路径。接下来我们深入实现它。
3.2 候选路径生成与图的状态管理
生成候选路径的核心是“临时修改图状态”。我们不能永久性地修改图,因为每次生成候选后图需要恢复原状,以便下一次生成。在YEN的原始论文中,这通过设置边权重为无穷大来实现。在我们的实现中,我们通过向Dijkstra函数传递“排除节点”和“排除边”的约束来模拟这一过程。
def _generate_candidate(
graph: Graph,
source: str,
target: str,
spur_node: str,
root_path: List[str],
A: List[Tuple[float, List[str]]]
) -> Optional[Tuple[float, List[str]]]:
"""
在给定的偏离点(spur_node)上,生成一条候选路径。
返回: (候选路径总距离, 完整路径节点列表) 或 None(如果无法生成)。
"""
# 1. 计算根路径的距离
root_dist = 0
for j in range(len(root_path) - 1):
u, v = root_path[j], root_path[j+1]
# 需要从图中找到u到v的边的权重
# 这里假设我们有一个辅助函数 get_edge_weight
w = _get_edge_weight(graph, u, v)
if w is None: # 边不存在,这不应该发生,因为root_path来自有效路径
return None
root_dist += w
# 2. 确定需要排除的节点
# 排除根路径上除了偏离点之外的所有节点(防止走回头路)
excluded_nodes = []
for node in root_path:
if node != spur_node:
excluded_nodes.append(node)
# 3. 排除特定的边(YEN算法的关键)
# 对于A中每一条路径,如果它的前i个节点与root_path完全相同,
# 那么这条路径在偏离点spur_node之后的那条边需要被排除。
excluded_edges = set()
for _, path in A:
if len(path) > len(root_path) and path[:len(root_path)] == root_path:
# 这条路径与根路径在前i个节点上重合
u = path[len(root_path)-1] # 原路径中,root_path最后一个节点(即spur_node)
v = path[len(root_path)] # 原路径中,spur_node的下一个节点
excluded_edges.add((u, v))
# 4. 计算偏离路径(从spur_node到target,避开excluded_nodes和excluded_edges)
spur_dist, spur_path = _constrained_dijkstra(
graph, spur_node, target, excluded_nodes, excluded_edges
)
if spur_path is None or not spur_path: # 没有可行的偏离路径
return None
# 5. 拼接完整路径
full_path = root_path[:-1] + spur_path # root_path包含了spur_node,spur_path也以spur_node开始,所以要去掉一个
full_dist = root_dist + spur_dist
# 6. 检查路径是否有效(无重复节点,除了spur_node)
if len(set(full_path)) != len(full_path):
# 路径中存在重复节点(形成了环),根据无环K短路定义,此路径无效
return None
return (full_dist, full_path)
这里我们引入了一个新的辅助函数_constrained_dijkstra,它是在基础Dijkstra上增加了排除边能力的版本。同时,_get_edge_weight用于查询边的权重。
def _get_edge_weight(graph: Graph, u: str, v: str) -> Optional[float]:
"""查询从u到v的边的权重。如果边不存在,返回None。"""
for neighbor, weight in graph.get_neighbors(u):
if neighbor == v:
return weight
return None
def _constrained_dijkstra(
graph: Graph,
start: str,
target: str,
excluded_nodes: List[str],
excluded_edges: set
) -> Tuple[float, List[str]]:
"""
带节点和边排除约束的Dijkstra算法。
excluded_edges: 集合,元素为 (u, v) 表示不能走的边。
"""
if start in excluded_nodes or target in excluded_nodes:
return float('inf'), []
dist = {v: float('inf') for v in graph.vertices}
prev = {v: None for v in graph.vertices}
dist[start] = 0
pq = [(0, start)]
while pq:
current_dist, u = heapq.heappop(pq)
if u == target:
break
if current_dist > dist[u]:
continue
for v, weight in graph.get_neighbors(u):
if v in excluded_nodes:
continue
if (u, v) in excluded_edges:
continue
new_dist = current_dist + weight
if new_dist < dist[v]:
dist[v] = new_dist
prev[v] = u
heapq.heappush(pq, (new_dist, v))
if dist[target] == float('inf'):
return float('inf'), []
path = []
node = target
while node is not None:
path.append(node)
node = prev[node]
path.reverse()
return dist[target], path
至此,YEN算法的主要部件已经齐全。我们需要将它们整合到一个完整的、健壮的实现中,并处理好一些边界情况,例如路径去重(B列表中可能产生相同的候选路径)。
4. 完整代码与深度优化
让我们将上述所有片段组合起来,形成一个完整、可运行的YEN算法实现。这个版本包含了路径去重、更好的错误处理和一些性能上的小优化。
import heapq
from typing import Dict, List, Tuple, Optional, Set
class Graph:
def __init__(self):
self.adj: Dict[str, List[Tuple[str, float]]] = {}
self.vertices: Set[str] = set()
def add_edge(self, u: str, v: str, weight: float, directed: bool = False):
self.vertices.update([u, v])
if u not in self.adj:
self.adj[u] = []
self.adj[u].append((v, weight))
if not directed:
if v not in self.adj:
self.adj[v] = []
self.adj[v].append((u, weight))
def get_neighbors(self, node: str) -> List[Tuple[str, float]]:
return self.adj.get(node, [])
def yen_ksp(graph: Graph, source: str, target: str, K: int) -> List[Tuple[float, List[str]]]:
"""
YEN算法主函数。
返回找到的K短路径列表,按距离升序排列。
"""
def dijkstra(start: str, end: str, blocked_nodes: Set[str], blocked_edges: Set[Tuple[str, str]]) -> Tuple[float, List[str]]:
"""内部Dijkstra,支持节点和边屏蔽"""
if start in blocked_nodes or end in blocked_nodes:
return float('inf'), []
dist = {v: float('inf') for v in graph.vertices}
prev = {v: None for v in graph.vertices}
dist[start] = 0
pq = [(0, start)]
while pq:
d, u = heapq.heappop(pq)
if u == end:
break
if d > dist[u]:
continue
for v, w in graph.get_neighbors(u):
if v in blocked_nodes or (u, v) in blocked_edges:
continue
nd = d + w
if nd < dist[v]:
dist[v] = nd
prev[v] = u
heapq.heappush(pq, (nd, v))
if dist[end] == float('inf'):
return float('inf'), []
path, node = [], end
while node is not None:
path.append(node)
node = prev[node]
path.reverse()
return dist[end], path
# 1. 获取最短路径
dist1, path1 = dijkstra(source, target, set(), set())
if not path1:
return []
A = [(dist1, path1)] # 确定路径列表
B = [] # 候选路径堆 (距离, 路径)
B_set = set() # 用于候选路径去重
for k in range(1, K):
prev_path = A[-1][1]
# 对前一条路径的每个可能偏离点(除了终点)进行操作
for i in range(len(prev_path) - 1):
spur_node = prev_path[i]
root_path = prev_path[:i+1]
# 计算根路径距离
root_dist = 0
for j in range(len(root_path)-1):
u, v = root_path[j], root_path[j+1]
# 查找边权重
found = False
for nb, w in graph.get_neighbors(u):
if nb == v:
root_dist += w
found = True
break
if not found:
# 理论上不应发生,因为prev_path是有效路径
root_dist = float('inf')
break
if root_dist == float('inf'):
continue
# 确定需要屏蔽的节点和边
blocked_nodes = set(root_path) - {spur_node}
blocked_edges = set()
for _, path in A:
if len(path) > i+1 and path[:i+1] == root_path:
u = path[i]
v = path[i+1]
blocked_edges.add((u, v))
# 计算偏离路径
spur_dist, spur_path = dijkstra(spur_node, target, blocked_nodes, blocked_edges)
if spur_dist == float('inf') or not spur_path:
continue
# 构建完整候选路径
total_path = root_path[:-1] + spur_path
total_dist = root_dist + spur_dist
# 路径去重检查 (基于节点序列)
path_tuple = tuple(total_path)
if path_tuple in B_set:
continue
# 无环检查(可选,但YEN算法通常保证无环)
if len(set(total_path)) != len(total_path):
continue
heapq.heappush(B, (total_dist, total_path))
B_set.add(path_tuple)
if not B:
break # 没有更多候选路径
next_best = heapq.heappop(B)
next_path_tuple = tuple(next_best[1])
B_set.remove(next_path_tuple) # 从去重集合中移除
A.append(next_best)
return A
关键优化与工程细节:
- 候选路径去重:使用
B_set(一个集合)来存储候选路径的元组形式。这避免了向堆B中插入完全相同的路径,提高了效率并确保了结果的正确性。 - 内部函数封装:将Dijkstra算法定义为内部函数,可以方便地访问外部函数的参数(如
graph),并使代码结构更清晰。 - 边权重查询:在计算
root_dist时,我们通过遍历邻居列表来查找边的权重。对于大型图,这可能会成为瓶颈。在实际生产环境中,可以考虑维护一个边的权重字典edge_weights[(u, v)] = w来实现O(1)的查询。 - 提前终止:在计算根路径距离时,如果某条边找不到(理论上不应发生),我们直接跳过该候选路径的生成,提高了鲁棒性。
5. 实战测试:从简单图到复杂场景
理论再完美,也需要经过实践的检验。我们设计几个不同场景的测试用例,来验证我们实现的正确性和实用性。
5.1 测试用例1:经典教科书图
我们使用原始资料中提供的示例图进行测试,这有助于我们与已知结果进行比对。
def test_basic_graph():
"""测试经典的6节点9边无向图"""
print("=== 测试用例1:经典无向图 ===")
g = Graph()
edges = [
('A', 'B', 8), ('A', 'D', 2), ('A', 'F', 4),
('B', 'D', 6), ('B', 'E', 4), ('B', 'C', 2),
('C', 'E', 3), ('C', 'F', 6),
('D', 'E', 1), ('E', 'F', 9)
]
for u, v, w in edges:
g.add_edge(u, v, w, directed=False) # 无向图
source, target = 'A', 'F'
K = 4
results = yen_ksp(g, source, target, K)
print(f"从 {source} 到 {target} 的前{K}短路径:")
for i, (dist, path) in enumerate(results, 1):
path_str = ' -> '.join(path)
print(f" 第{i}短: 距离={dist}, 路径={path_str}")
# 预期结果(距离可能因浮点数略有差异,路径一致即可):
# 1. A-D-E-F (12)
# 2. A-D-E-C-F (12) 或 A-B-C-F (16) [取决于实现,当距离相同时,选择哪条取决于heap排序的稳定性]
# 3. A-D-E-B-C-F (15)
# 4. A-B-C-F (16)
运行这个测试,你应该能看到算法正确地找出了前4短的路径。注意,当两条路径距离完全相等时(如12),哪条被排在前面可能取决于Python堆排序的细节,这在实际应用中通常是可接受的。
5.2 测试用例2:有向交通网络
模拟一个简单的城市交通网络,其中有些道路是单行道。
def test_directed_traffic_network():
"""模拟一个有向交通网络,寻找备用路线"""
print("\n=== 测试用例2:有向交通网络 ===")
g = Graph()
# 模拟一个区域,边表示道路,权重表示通行时间(分钟)
edges = [
('Home', 'A', 5), ('A', 'B', 10), ('B', 'Office', 8),
('Home', 'C', 12), ('C', 'D', 7), ('D', 'Office', 6),
('A', 'D', 15), ('B', 'D', 4), # 一些连接路
('D', 'B', 3), # 单行道!D到B可以,B到D不行(上面已定义)
]
for u, v, w in edges:
g.add_edge(u, v, w, directed=True) # 有向图
source, target = 'Home', 'Office'
K = 3
results = yen_ksp(g, source, target, K)
print(f"从 {source} 到 {target} 的通勤备选路线(前{K}快):")
for i, (time, path) in enumerate(results, 1):
path_str = ' -> '.join(path)
print(f" 备选{i}: 耗时={time}分钟, 路线={path_str}")
# 这个测试可以验证算法在有向图中的正确性,并展示实际应用价值。
# 例如,最优路线可能是 Home->A->B->Office (23分钟)。
# 次优路线可能是 Home->C->D->Office (25分钟) 或 Home->A->D->Office (26分钟)。
5.3 测试用例3:通信网络路由(寻找冗余路径)
在网络通信中,我们经常需要为关键数据流寻找多条不相交或部分不相交的路径,以实现负载均衡或故障冗余。
def test_network_redundancy():
"""在通信网络拓扑中寻找K条短路径,用于冗余路由分析"""
print("\n=== 测试用例3:通信网络冗余路径 ===")
g = Graph()
# 节点代表路由器,边代表链路,权重可以是延迟、成本或跳数
# 这里我们用跳数作为权重(简单起见)
topology = [
('R1', 'R2', 1), ('R1', 'R3', 1),
('R2', 'R4', 1), ('R2', 'R5', 1),
('R3', 'R4', 1), ('R3', 'R6', 1),
('R4', 'R7', 1), ('R5', 'R7', 1), ('R6', 'R7', 1),
('R7', 'R8', 1),
]
for u, v, w in topology:
g.add_edge(u, v, w, directed=False) # 假设链路是双向的
source, target = 'R1', 'R8'
K = 5
results = yen_ksp(g, source, target, K)
print(f"数据包从 {source} 到 {target} 的前{K}条最短路径(按跳数):")
for i, (hops, path) in enumerate(results, 1):
path_str = ' -> '.join(path)
print(f" 路径{i}: 跳数={hops}, 路径={path_str}")
# 在这个网格状拓扑中,你会发现多条跳数相同的路径(例如,长度都是4跳)。
# 网络工程师可以利用这些信息来配置多路径路由协议(如ECMP)。
运行所有测试,你将看到算法在不同场景下的表现。这些测试不仅验证了代码的正确性,也展示了YEN算法在物流、交通、通信等领域的实用价值。
6. 性能分析与进阶探讨
实现一个能工作的算法只是第一步,理解它的性能边界和优化空间同样重要。
6.1 时间复杂度与空间复杂度
YEN算法在最坏情况下的复杂度并不低,这是由问题本身的性质决定的。
- 时间复杂度:大致为 O(K * n * (m + n log n)),其中
n是节点数,m是边数,K是要求的路径数。这是因为在最坏情况下,我们需要为前K-1条路径中的每一个节点(共O(Kn)个)运行一次Dijkstra算法(O(m + n log n))。 - 空间复杂度:主要消耗在存储A列表和B堆中的路径上。在最坏情况下,可能需要存储 O(Kn) 条边信息。
对于大型网络(例如上万节点),求解较大的K值可能会非常耗时。在实际应用中,K通常不会太大(比如10或20以内),用于获取少数几个备选方案。
6.2 潜在优化方向
如果你的应用场景对性能有极致要求,可以考虑以下优化策略:
- 使用更快的单源最短路径算法:Dijkstra是核心子程序。对于特定的图类型(如道路网络),可以使用更快的算法,如A*搜索(如果有好的启发式函数)、Contraction Hierarchies(CH)或Customizable Route Planning(CRP)。在我们的实现中,将
dijkstra函数替换为这些算法的接口,可以大幅提升整体速度。 - 候选路径剪枝:如果候选路径B堆变得非常大,可以设置一个上限,只保留距离最短的M个候选(M > K)。这虽然可能丢失一些理论上的第K短路径,但在许多实际应用中,排名非常靠后的路径意义不大,此方法能以精度换取速度和内存。
- 并行化:YEN算法中,为同一个
prev_path上不同偏离点生成候选路径的过程是相互独立的。这是一个天然的并行点,可以利用多线程或分布式计算来加速。 - 增量计算与缓存:每次调用Dijkstra都是独立的。可以考虑缓存从某个节点到终点的最短路径树(SPT),当图结构不变且多次查询同一终点时,可以复用,避免重复计算。
6.3 处理负权边
一个重要的限制是,我们实现的Dijkstra算法(以及基础的YEN算法)要求图中没有负权边。如果存在负权边,需要使用Bellman-Ford算法或其改进版本来计算最短路径,但这会引入负环检测的复杂性,并且YEN算法在存在负环的图中定义K短路本身就有问题。在绝大多数实际应用(如距离、时间、成本)中,边的权重都是非负的。
最后,代码写完了,测试也通过了,但真正让我觉得这个工具好用的,是在一次模拟网络故障演练中。当主用光缆路径中断时,系统能瞬间从我们预先计算好的“Top 5最短路径”列表中选出第二条可行的路由,业务几乎没有感知。这种“有备无患”的能力,正是K短路算法带来的最直接价值。你可以尝试用不同的图、不同的K值去运行它,看看在你自己设想的场景中,它能为你挖掘出哪些意想不到的优质备选方案。
更多推荐



所有评论(0)