数学建模社区-数学中国

标题: 最短路径算法Python代码 [打印本页]

作者: 2744557306    时间: 2025-1-13 17:26
标题: 最短路径算法Python代码
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。. T3 w1 q% C  ]' n, k$ U

; M( U) P( t1 Y# ^% q# v4 x& T## 1. Dijkstra 算法
) ?2 A" G- j9 k* i2 u( A
1 Y; N) |6 ^4 \* Q6 i( y+ l6 dDijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。7 ]% `/ ~- s6 b/ g8 ]# I

- v" s4 O; e( C; s. P8 l### 原理步骤9 o0 g5 x! i" z: F4 a

$ A8 G( ^" X$ O$ t: u9 d# K8 t" e3 g1. **初始化**:
" B" j; u. G3 Z- S7 p   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。
$ H7 f9 Z9 \; D0 @3 Z& B4 P   - 初始化一个空的优先队列,用于存储待处理的节点。) ^6 o) S% h& P  d" d

5 i3 B* s9 Y% p/ Y9 J0 S) r2. **处理节点**:# x3 j$ [& J: \3 K! |
   - 从优先队列中选取距离最小的节点作为当前节点。
6 g" X  [+ @9 @( s   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。: v, ~, D& ~1 q* S6 P

. F( j1 ]  Z8 y4 }! j( o! D3. **重复处理**:
; S; L: j& O! K   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。7 W& S8 b* f5 a% j
) P2 e1 K7 V+ @9 R3 Y% {! C
### 示例代码  E* [/ e) c9 W9 ^% K% ~
, u9 U  J1 ]' f$ C
```python  T5 @2 O5 r0 m# F* I8 w, x( p
import heapq
/ \, R& S) j* O* q+ ]3 r2 z7 B' h5 l1 Q2 J
def dijkstra(graph, start):/ W. j. N# {. J; l9 m6 U+ D
    # 图的表示为字典,键为节点,值为邻接节点及其边权
& d- Q4 n* A' F0 Y2 }5 H0 K8 k    queue = []. g+ `3 |/ I9 E
    distances = {node: float('inf') for node in graph}
& E" G$ I- z5 Y& j  S    distances[start] = 0
  v$ v; W+ Z  v+ s    heapq.heappush(queue, (0, start))  # (距离, 节点)2 m* Q1 e. A" H; {, p9 N# u1 b

* D6 x2 Y5 v( d9 E  z# L7 ]$ ~    while queue:6 l. v0 R; h+ h# C$ n+ }" k
        current_distance, current_node = heapq.heappop(queue)
& @7 w* Z9 s* r- S8 {# u% ?- o
; S: E! d# B' M, o1 O% p; w2 N        # 只处理当前节点的最短距离
+ l3 {( A) u% T: g+ U$ S9 K        if current_distance > distances[current_node]:
: V2 Q0 k% m6 e# q: b            continue4 Q, E( U5 f4 r6 j+ e9 \
0 ~8 e. p2 V2 x7 h1 h; `
        for neighbor, weight in graph[current_node].items():
4 m3 q3 Z3 E  B. ]7 ]& W' g% p            distance = current_distance + weight: @! u$ _3 B+ z& x% q

! }# F/ J1 ]/ E/ r' X) g4 I% a            # 更新邻接节点的距离% s4 \+ O' l) L% W; p
            if distance < distances[neighbor]:. o* E. u- p5 Y3 I
                distances[neighbor] = distance, I+ l" r1 g7 N, ^; z5 M$ b7 A# l
                heapq.heappush(queue, (distance, neighbor))# A# m7 y+ T/ m

+ T  J- e9 Y3 l& d+ ~* {3 m9 i    return distances
& a( u/ |" r( I( k2 `
+ C( ?5 j2 X5 W" ^: ^# 示例图
1 b0 M# ]8 m8 D6 E  w& fgraph = {
. z5 G4 L9 y3 F& N1 I* i    'A': {'B': 1, 'C': 4},  x, M! ?3 a/ [( E
    'B': {'A': 1, 'C': 2, 'D': 5},
$ T1 ~% {0 a* n9 }% y% b    'C': {'A': 4, 'B': 2, 'D': 1},
! F1 @4 a3 {( Z: N( R/ n    'D': {'B': 5, 'C': 1}," ]" L5 |: w2 K: h9 m8 p
}# X/ v& u8 w+ v, s

' `! W# w) W/ `! B# v6 bstart_node = 'A'
% z9 l4 d" r: l& x) _shortest_paths = dijkstra(graph, start_node)
" a7 Z/ ]# p3 P; Zprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
: Z2 ^. h8 n0 C+ p, o3 ]$ V```0 ?& i) Y* u7 T. b+ s
4 c5 \2 G7 a% Z& Y7 {( }! V
## 2. Bellman-Ford 算法& a/ r+ W6 v4 M

* T4 P0 w: z: O0 T- \Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。; y& \( `* a- }9 ?2 a

$ k% j: \% e$ {( {% B% {- v! ]& a( v### 原理步骤
  b6 L8 x& P: M2 w9 t  K" l
5 @) Y3 @4 r9 Q# C% _; s7 h. T1. **初始化**:, J; n! ], L. `; n
   - 设置源节点到自己的距离为0,其他节点为无穷大。0 a: d" U; [8 Q1 z

3 o* |: L& P6 g. w2. **松弛操作**:
" o2 {4 h7 I6 g& E   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
/ A6 y! a# n- R- k- }4 D: B% [  H! G- b4 j2 Z
3. **检查负权回路**:
+ H, a! M/ a  O1 n1 w   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。, g" j- r7 Z3 c! L+ f

) f; m+ w' ^  E4 {! Z/ D' K0 g9 N### 示例代码
$ b9 L7 Z% n: Y. U+ B- H( ^# U: A' R/ L; x, K- K5 ]; z% o
```python7 D% O& n" j$ m' Y
def bellman_ford(graph, start):6 a* N; S8 l9 g  Q. d" J$ b2 z9 O
    # 初始化距离
/ s) v& A0 J6 L5 ?" \6 A8 b    distances = {node: float('inf') for node in graph}
+ ?) n2 y+ j! e! R( K1 e    distances[start] = 0
* f2 V4 r3 H9 A2 J6 B$ o# P7 w; b- n2 z* w
    # 松弛操作
* T0 }* X. _: W+ u    for _ in range(len(graph) - 1):
5 q) Y9 g. w8 q+ W5 B        for u in graph:
7 ?8 J$ P- Z& G; Y' t            for v, weight in graph[u].items():
, X3 U4 i  Y  j( y5 _4 q                if distances[u] + weight < distances[v]:
; ]3 W5 u( r- ^* u8 K6 T                    distances[v] = distances[u] + weight
( B' S; v% h1 r- ^
( c) x% v, d# `3 U9 v) m    # 检查负权回路
8 q$ D4 l' s4 e  {  O; W  n    for u in graph:( Y  ~2 P: M! n/ c. ~' O
        for v, weight in graph[u].items():
( d# U* I7 l) y1 j, z8 b) ]  J+ D            if distances[u] + weight < distances[v]:
) Z8 J1 A' t. s; d; y                raise ValueError("Graph contains a negative weight cycle")
; {- |+ E5 A4 [0 v
3 A( b7 b$ `5 ~+ u1 s    return distances7 b6 v# k" M+ }' n" u: W

# F) ~& l9 ~0 B7 }7 _7 ~0 L# 示例图(带有负权边)
6 T5 A" O# {9 F( |! Wgraph_with_negative_weight = {: E2 ~" O" P1 w4 n) ?1 J
    'A': {'B': 1, 'C': 4},
8 J: C' O9 E6 o! {, }    'B': {'C': -3, 'D': 2},
# F" I$ ?; C0 @" Y: G    'C': {},: l/ @/ |  o8 Q# U* N" @
    'D': {'A': -1}
5 q+ G5 _/ C$ y+ `}: ?+ ^, P/ R6 X
" N* ?5 }6 m1 c2 x" n4 \
start_node = 'A'
7 Q. M4 J* a7 B9 [7 _shortest_paths = bellman_ford(graph_with_negative_weight, start_node)
" U1 H& P' j. i. y  R0 Sprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
* R6 d; \1 |: M" J0 J4 P' }```
! G* L% z5 v1 n( L8 O+ w. U5 y- n0 a8 d9 W) w
## 3. Floyd-Warshall 算法
: n4 _+ a" A2 T) R# d+ X9 o
& m! Q1 a! g2 u( |2 y) XFloyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
# ^5 T5 o  x! a2 m' Q! g% w4 N: y( F0 k9 F, |+ f( {+ e8 y
### 原理步骤
8 T/ M! C5 y, W$ @
/ n  j& n% \: V& l; ]5 C1. **初始化**:
6 e2 `! e/ O7 \2 a   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。
9 k) g+ L: S: v& D* j4 J6 @- f# t: f. N" g( ]
2. **更新路径**:/ C5 v+ }9 q+ o0 {' K; T2 C) k/ j
   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
  R2 X1 m5 t$ |" a! j3 b; g8 L% w1 W$ D
3. **输出结果**:
' P1 q6 o0 }5 @8 j   - 最终得到的矩阵即为每对节点之间的最短路径长度。* O+ |& n- x; c" k+ K$ z

- ?5 y0 G- T$ k2 n### 示例代码
$ X: u5 J& O/ i# F4 `5 L- @( X3 ]2 j
```python
6 K: b) V2 H  C* ^7 c) s: b8 Vdef floyd_warshall(graph):* U& A% I5 T( m, ~* R
    # 初始化距离矩阵
- y. u& k9 K7 Y7 B' {0 L, Q    nodes = list(graph.keys())9 _8 L/ Q/ v% s0 t) u/ z! ]
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}
) x1 r+ G2 w- f  r9 C% E& j( K* g! K
    for u in nodes:: c- j) P2 Y9 j
        distances[u][u] = 0  N  E! F) K7 z. {# X/ P$ G
        for v, weight in graph[u].items():
- s1 J4 ?5 b' }' M" H' C" X            distances[u][v] = weight
$ ?: S! Y) x( C! K( W' C
+ ~% g, _6 k" ^9 i% g  z    # 更新路径* W; w5 B5 ^5 P7 N9 ^- \( m
    for k in nodes:
4 t9 \; _- S! j" R; B" D4 z        for i in nodes:4 @( e, j2 q$ h
            for j in nodes:( K/ ]1 T4 @/ K" k$ X4 J3 F# b: Y
                if distances[i][j] > distances[i][k] + distances[k][j]:
- M4 f/ u2 t& d8 C                    distances[i][j] = distances[i][k] + distances[k][j]0 S9 y( T0 H0 z& P# z, v- H
/ Y2 F! s5 s% A+ ?- b  B, }
    return distances0 I1 V' Z" W- i& I! K$ `
3 A1 |- ]) |) ^% G- Z1 G
# 示例图(可以含负权边)
# C* }# v2 F3 Hgraph_for_floyd = {3 u; v8 h# }& _/ n  W- R
    'A': {'B': 3, 'C': 8, 'D': -4},
, I% c- _4 M/ h  J0 @2 `; B7 k# ?    'B': {'C': 1, 'D': 7},
3 S5 g. L& ^; i' ^) I" Z    'C': {'B': 4},* y0 o6 \4 F& O8 c3 ]
    'D': {'A': 2, 'C': -5}. g7 T7 `, a* p& h
}
* }5 g" I/ V8 G, ~
3 Y+ h9 t1 Z0 z1 v! |4 |shortest_paths_matrix = floyd_warshall(graph_for_floyd)( E. _( l# v2 z* _. Z; O
for row in shortest_paths_matrix.items():
7 J& m0 C( L) D8 P7 n    print(row)& d9 q0 `2 w9 r3 b/ w+ s: |
```
6 w% O! _6 |* h+ U: ~( r, J1 q+ P
## 总结. M2 C: Q5 Z2 o1 h( M6 \: x
- T0 o1 w  ?9 c. |6 _" r$ y9 c( t
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。) V" G3 g. C6 o$ Y
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。* t- O1 D, G3 d" y0 v) c
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。
: u5 r5 P" g2 `2 K0 y
5 n  r) o* D1 N不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!
4 ?5 `  M; Y1 q) u4 D% e1 z9 W7 U- T$ b% v4 {0 K& B$ ~$ a% s2 r

& A: I) F3 P" @  K5 u2 K7 L/ r0 d. L9 k- Y, P! y1 }6 i. u

最短路径算法Python代码.docx

13.29 KB, 下载次数: 0, 下载积分: 体力 -2 点

售价: 2 点体力  [记录]  [购买]






欢迎光临 数学建模社区-数学中国 (http://www.madio.net/) Powered by Discuz! X2.5