% }. m6 Z) y- E6 K+ G4 c7 I```python 1 {+ `' \( U, O4 n' v8 wimport heapq# p" a6 H$ A1 O! L7 E$ |
5 Z. f' N$ @0 }$ J5 z: r- c! ?2 p. X( l
def dijkstra(graph, start): # p0 c+ Z8 Q( a1 U- B) t # 图的表示为字典,键为节点,值为邻接节点及其边权 ( M5 o# I3 |5 K5 E$ \ queue = [] B5 S% S0 J9 d0 ~ distances = {node: float('inf') for node in graph} 0 A; G) J! J& v3 F, h distances[start] = 0 5 D2 n; a) Q# P( E C0 g% M heapq.heappush(queue, (0, start)) # (距离, 节点)8 T: k O- x( U$ r e5 \, K' }
* H- ]% K6 T' b( y3 [
while queue: " u7 K* E5 X7 B current_distance, current_node = heapq.heappop(queue) i+ d" x; k: G8 N+ [: R
" E. S, p Y& b4 ]7 q& {2 m
# 只处理当前节点的最短距离) L" \6 s5 F/ m
if current_distance > distances[current_node]: + Q1 |8 j8 n( U. y/ C continue3 Q) t( ~5 i* K$ D% e
1 t& P5 I! Y: U8 w
for neighbor, weight in graph[current_node].items(): @' |- t) |9 k5 D! a distance = current_distance + weight 3 I! d/ M' d/ `+ C% U; z b8 u- q 0 Z0 ]( Q5 s. w # 更新邻接节点的距离5 U/ w& x& l; {1 j1 ]2 L
if distance < distances[neighbor]:4 ]2 [/ r' T2 N
distances[neighbor] = distance9 y9 t4 s( W H) M0 ^! o& h
heapq.heappush(queue, (distance, neighbor)) $ V1 \6 e2 u4 j- \ / O& x5 }& J5 Y return distances 8 H8 q- r7 I1 C3 j1 X* S 8 o0 f% `; N) W1 }4 l2 v3 k# 示例图 5 T! H. C8 A: \7 Y4 X2 V- D/ qgraph = {4 S8 I7 J8 p) c! }3 @. v2 }. c4 j
'A': {'B': 1, 'C': 4},7 A, I; J$ E+ j2 z7 k
'B': {'A': 1, 'C': 2, 'D': 5}, * S! C# Q: R) [3 W" V 'C': {'A': 4, 'B': 2, 'D': 1},: L Q" Y. O5 h* h7 `- m0 `
'D': {'B': 5, 'C': 1},& K# e# f, Q6 W- ^
}# v+ M1 Z) V# [/ i
+ g; l+ {% z# B- X
start_node = 'A'0 `; W3 j) K7 v& z4 }# x
shortest_paths = dijkstra(graph, start_node)7 U) _- l- F# z! C
print(shortest_paths) # {'A': 0, 'B': 1, 'C': 3, 'D': 4}& _ M, C1 ~5 a6 ?! _+ q
```, F" l8 _0 o9 A7 d# r4 H/ a
, \' n" e P5 v# v4 C# M8 |( }( I## 2. Bellman-Ford 算法' r% O: x0 w. Q: Y6 R- y
# C0 B- u9 Y( L& [/ TBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。 . c8 a Z0 E: Q & X3 O/ Y9 L7 v' \/ h' _### 原理步骤6 g3 t! w; b# H' _# G. n. \, {0 h
8 E5 F' y& G9 z
1. **初始化**:4 @1 n$ l7 |- `. S9 d/ Z
- 设置源节点到自己的距离为0,其他节点为无穷大。6 O8 q1 [) J1 k7 G/ \& q
0 G& b9 T" @8 K: [7 p2 {& w
2. **松弛操作**: + l' S- w8 k& X6 U, p, d$ f - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。 * G7 p" \; q- w c8 Y! B2 u3 t% ]2 h7 @
3. **检查负权回路**: 5 K7 {& D3 Q7 |' `; k1 ? - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。 . J. h6 h- @) F5 D/ I. G# x4 W 6 Z7 E4 S, l( E3 U2 n1 o0 m### 示例代码& B- d9 D1 \/ r- j
, Y1 T+ f7 D; D+ l; {+ K; E
```python 9 x- J/ F8 r8 ^# xdef bellman_ford(graph, start): 7 d9 d* j" }* P6 T; E3 f8 G# f, d # 初始化距离( C) |8 J$ s( k4 D% q, k3 N
distances = {node: float('inf') for node in graph}4 g6 G6 i: Q4 W n+ t, P8 Y a
distances[start] = 0 + J3 [, i8 b+ {" G . V3 H5 @) z' r; y4 v0 O # 松弛操作 ; {4 p: f( t( n6 w: }1 z for _ in range(len(graph) - 1):: M$ Y! [- F4 T2 i0 ~
for u in graph: 9 r* V( ^# s. u6 g7 D for v, weight in graph[u].items():% I; t. {; i1 `5 V! J
if distances[u] + weight < distances[v]: 8 z1 P. P9 W6 R$ z distances[v] = distances[u] + weight ' h+ a$ z1 p% S6 F. r / `; [: ` l# g # 检查负权回路) v! Z- m4 [# e3 m: G9 X- i
for u in graph: 3 q" y* h6 L4 w, s# O for v, weight in graph[u].items(): 9 M0 m$ z- d: D if distances[u] + weight < distances[v]:2 k$ G1 l1 v6 `- {$ O* o
raise ValueError("Graph contains a negative weight cycle"). ~2 [ }& t) }: B: ?* X
& F% l$ v8 U( j
return distances 5 G1 Q! g% W3 \( k! \9 ?$ B6 x. R) z& X
# 示例图(带有负权边)9 d" K1 h, V2 N( L! G; c; w
graph_with_negative_weight = { 8 C* N( P# \* P7 r6 E# D 'A': {'B': 1, 'C': 4}, - u0 R, a( G* }+ G) i: [, g 'B': {'C': -3, 'D': 2}, ! o/ ^0 Y1 c, v- @ 'C': {},+ k1 s1 | G6 _# K2 X4 l$ h" n. O' k
'D': {'A': -1}4 k; S" T8 \) x% N
}, x8 m2 y* D6 K8 a4 d
2 X4 ]- A0 ?, z) h: y% v
start_node = 'A', d' b5 K0 ^7 Q0 p! D- i% Z' `
shortest_paths = bellman_ford(graph_with_negative_weight, start_node); C( p, v$ U& e( Y
print(shortest_paths) # {'A': 0, 'B': 1, 'C': -2, 'D': 3} 6 c. _3 w* I }3 r1 a. B, y```. }7 U1 {/ n, g3 |& d5 Y
8 D1 L: _: b0 }8 n
## 3. Floyd-Warshall 算法 ; l1 j7 v9 e: e/ g0 ], g% x0 z; u M/ u" e- \& l' D) ^Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。 3 H. N/ R% a' D8 ]& H : l& @* W' b$ r, K### 原理步骤3 Z1 ?5 M, d( h# d- j3 P
" J8 ]& y! v4 x% I7 v0 L
1. **初始化**:% `% D0 u9 B4 H6 p
- 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。 7 `$ ^! k$ F/ m+ A o$ M I # y6 E4 V! V3 ]( _8 {2. **更新路径**:; p0 A/ }: x* ]/ D& ]5 I
- 三重循环遍历所有节点,以每个中间节点尝试更新路径。 ( P/ m$ S! W) L* B; t3 s + y9 y* [0 A" Q4 [0 K- B3. **输出结果**:( p' @* D4 z8 i, m& j- z: C7 f
- 最终得到的矩阵即为每对节点之间的最短路径长度。 , ~! ]: \3 [0 D2 C$ z 1 J! _) z' @ t. ]+ s; A### 示例代码7 j0 @, t8 g+ g9 T/ E
5 u6 C5 J4 g/ Z; I, a* T3 i6 J+ @```python( w. ~" B# J9 L/ S9 T
def floyd_warshall(graph): . r, r$ B* f+ a/ a5 W6 } # 初始化距离矩阵 . K0 n) G1 d) e+ e; @1 m2 t4 i nodes = list(graph.keys())- ^( n% N S- ^0 k) S1 i4 P
distances = {node: {n: float('inf') for n in nodes} for node in nodes} 2 O) i- h& \7 A9 S' c 7 m0 |8 o; C! X for u in nodes:8 u4 D. L2 f; X) s* i# K
distances[u][u] = 0 m8 n% Z* { l, K
for v, weight in graph[u].items(): , \5 [; n) K2 c, Z3 X distances[u][v] = weight - m5 n7 @" h8 c5 |2 t7 h. c } 9 X. q" d1 N! l- o( G3 ^ # 更新路径9 p4 e" d, |' E6 T( n# E
for k in nodes: / ]3 F1 z5 G1 `/ B3 d, L' N for i in nodes:9 h- \7 j: i# F
for j in nodes: & j0 y) y& ]& i- H4 C if distances[i][j] > distances[i][k] + distances[k][j]: ; ~( ?7 t! P1 _5 V( l5 S distances[i][j] = distances[i][k] + distances[k][j]& x! Z5 r! v. I; b