数学建模社区-数学中国

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

作者: 2744557306    时间: 2025-1-13 17:26
标题: 最短路径算法Python代码
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
! u. Q& b! o+ g& m7 K: l" \9 n' S; P# _
## 1. Dijkstra 算法
  T" x' n% F% V1 ?
- Y4 ]' j/ t- F9 G, y( X; }: G: K" CDijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。8 C% ~) R2 P  @0 D/ `: y& ~: F
: ~4 `3 n- v9 A, P
### 原理步骤
! N6 }0 G; z/ Y4 G. `* Z# \" Q4 W3 M, J+ j
1. **初始化**:- e/ B0 h2 t3 o, r# B' E9 ^
   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。& o4 q" t9 Z4 w7 j2 J/ `& ^/ ?: ~2 s
   - 初始化一个空的优先队列,用于存储待处理的节点。, X. B9 H$ c3 U7 G+ \$ X3 S' C

0 B& B: ~: v1 H1 N2. **处理节点**:
* R$ R+ z1 x+ s0 A: P9 r7 X( Z   - 从优先队列中选取距离最小的节点作为当前节点。
( k8 `* F0 R: }$ w4 f   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
; H! Z1 N4 G, f1 R! c0 S$ B' w7 w- b! V! e; Q
3. **重复处理**:( w) c8 c- O- C- _# E
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。, K+ a7 x" T0 D8 B5 ~9 q

+ o, k: O* X" J& X: A### 示例代码3 c; E! m/ z- j: c0 k
6 p' x( w/ O5 A8 _& \- A& i
```python* |1 F0 ~) ~8 I- j" W
import heapq
" T1 x6 U- R$ @+ D. @, V
4 Z$ M- C% n6 o; w* U( edef dijkstra(graph, start):1 L! R/ o3 i+ G- M" Z7 B* h0 e
    # 图的表示为字典,键为节点,值为邻接节点及其边权
" V) A# ~) h$ C- b  R; q& x" Q    queue = []
0 _/ y2 j, V) t* q, G: F4 P/ t* _    distances = {node: float('inf') for node in graph}6 C" S+ w/ T. m
    distances[start] = 0
2 J: {1 Y: g. M1 Z    heapq.heappush(queue, (0, start))  # (距离, 节点)
. g+ e) }# O9 k# o9 j
  m  M/ {5 g/ g' J5 c    while queue:
7 C  `, |* H3 d0 ~: z- n        current_distance, current_node = heapq.heappop(queue)8 A4 J3 a1 P5 z! Z7 x5 f9 X2 t$ s) W

) S6 z2 x8 a/ b% {, S        # 只处理当前节点的最短距离
! x) x+ u/ v2 _- ?        if current_distance > distances[current_node]:
7 @" F/ G8 ?6 K9 N0 H            continue
  W& Z; L5 D2 T& g' {+ t' F( Q$ h3 R8 u" i- `# z! B; b, g
        for neighbor, weight in graph[current_node].items():
, G# n. [! k3 ~. e( S( c, G            distance = current_distance + weight* r) y7 _- F+ D

2 p) e2 g0 i% u; _; k6 a  }            # 更新邻接节点的距离9 a5 J( {& e! F, F; P
            if distance < distances[neighbor]:5 d* W2 y+ E) f% t% u
                distances[neighbor] = distance% c1 T" \5 k' n5 C" ?# J
                heapq.heappush(queue, (distance, neighbor))
7 f' |, X2 P) Q
2 h: k' ]) m! s    return distances
( O2 b1 L/ q. ~* g+ r, C" c; G/ ]  {: f. U9 E9 ^
# 示例图! }0 s6 m3 z) ]# R
graph = {
$ O: }5 z, h, H/ ^. r! t    'A': {'B': 1, 'C': 4},5 L+ a2 N9 B* N
    'B': {'A': 1, 'C': 2, 'D': 5},
/ X% \0 u* `4 P3 w0 n    'C': {'A': 4, 'B': 2, 'D': 1},$ R3 t% S2 @4 p
    'D': {'B': 5, 'C': 1},
9 O: m5 }# V% {4 `: I6 h: U}
0 W" t3 @0 v; P: a4 V; \% q6 E0 z% {  X  Z, g1 g9 M5 E; j
start_node = 'A'# G/ G# b( A* Y5 e" n
shortest_paths = dijkstra(graph, start_node)5 j5 G9 _3 C' W& \6 g; o- b
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
4 @. _( Q1 S" u% o```
6 R# I3 S9 N. B& k' [! z# t7 S) H3 Z4 g8 H- n. z! Q4 D
## 2. Bellman-Ford 算法2 h9 E% a' \) O) I2 X: b! x
9 T3 M' x$ M3 Y8 p& ^6 d, ?0 \
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
, w; i% }* j  y; w- C+ v0 K$ m1 \- i& g. U3 H$ o: |: g
### 原理步骤
( Q0 B3 W4 _! Z9 ~. g' E) [/ ?% n  j  }# ]8 A9 E% Y) h$ V
1. **初始化**:
3 Y6 n& J5 N3 i7 a7 g, }   - 设置源节点到自己的距离为0,其他节点为无穷大。) M' @) O+ d& r8 Z) J5 \( T2 [

3 i8 \0 V- f) w" k* i2. **松弛操作**:/ m# j1 D, g6 B0 w
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。8 ^6 l2 P* p4 @: ^; C" G+ @

2 H! e/ H) u) v; `% G3. **检查负权回路**:
0 ]. o' L: s1 f! |. z$ E   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
# p; {" f2 t0 f& A% q1 Q, N- W2 ?6 }. e# e( A  `9 C9 s
### 示例代码
, g' `0 x0 I' t) I- P* ]. u
2 L: E( L1 i# H0 X4 n$ g```python
2 r+ n% d1 U& O" h6 O: s( ldef bellman_ford(graph, start):+ D% v; r- f8 g0 H7 A
    # 初始化距离1 P8 w5 l' x7 m9 E
    distances = {node: float('inf') for node in graph}9 W3 x! Y1 D. D1 U" z1 B
    distances[start] = 02 M7 h& Q6 d- t5 k0 i9 b  S* [; u2 B

& U& p$ n8 h, Q# I+ s) V    # 松弛操作; b& y+ O! A' \$ C. z" H
    for _ in range(len(graph) - 1):
! v8 X9 w. }' o0 c3 \6 U- o+ Z, D        for u in graph:1 b& @0 |+ x2 d: ~6 g* Z1 {
            for v, weight in graph[u].items():0 G7 S  E3 }/ U/ N8 _# S" k6 m
                if distances[u] + weight < distances[v]:
/ o; U, y4 ?! V* g0 k0 m: Q( M                    distances[v] = distances[u] + weight
! ^+ k8 d. I6 y6 X
0 T# |( @; x! V# f" n    # 检查负权回路- ]9 U* X2 Y% d& V% `' a# K
    for u in graph:
0 w- Y; G7 K1 Z2 ^        for v, weight in graph[u].items():
* h( ]1 @% \* y  J; U            if distances[u] + weight < distances[v]:3 q/ ^/ X! K( H. p* W
                raise ValueError("Graph contains a negative weight cycle")- ^2 M. p* t2 N6 x

! Q( F, O$ X. _    return distances% N: _% |1 g- x& l) M6 A3 k

) g  x0 L& Y" M5 H$ g' ^& h# 示例图(带有负权边); F3 o- u8 F1 a7 M# P5 l
graph_with_negative_weight = {$ U3 f5 g3 l! F, F3 w
    'A': {'B': 1, 'C': 4},: x9 x& x4 u8 |0 p' |/ e0 U3 v$ c  M
    'B': {'C': -3, 'D': 2},
' T$ |/ \1 N8 D" {7 O    'C': {},
# C/ d( A. F, N2 t8 ^    'D': {'A': -1}
+ Q  e+ L, ?; g' _5 H$ `1 t7 w  a}
. M7 l- d6 y6 V/ Y4 v/ B3 E+ w
: ?8 J. Q9 I7 @/ }- Astart_node = 'A'
/ f7 i# G9 H/ V+ A7 N" hshortest_paths = bellman_ford(graph_with_negative_weight, start_node)
' Y, A' R( t3 _/ A& N7 @3 ]* Y! Tprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
% e0 o  j$ C  h6 A" h```
: \7 U0 y7 Q" G" Q3 m2 X" |+ [. m9 b# h& ~5 E2 h9 ^: a
## 3. Floyd-Warshall 算法" Y8 p2 L$ A; Z( J0 t
" r' X- q# [* B7 q3 _
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
: N2 l0 s  W! Z5 G* u7 {8 K9 X/ e* \9 m5 c( l; b% E8 M3 z' N; F- m" G% `
### 原理步骤
$ ~9 H2 Q# I9 ^4 y8 I% i. _
$ \! |5 j4 _) ^/ G. P& Z. d1. **初始化**:! v6 m! m% [5 T/ I- a
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。
  a2 y# D* ~' Z) Y+ X8 ~
- ?; q4 r2 d/ w- {6 O. D5 q# z$ @2. **更新路径**:
5 e1 n5 i; H7 M" H- y   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。2 R3 K- n8 ?" O+ r! w; C% @
  P& I% k  _& S6 q; P; Y
3. **输出结果**:6 N, b8 P! w% M. J( X5 _% z
   - 最终得到的矩阵即为每对节点之间的最短路径长度。
6 [# e( m( u7 i/ a( w( F7 V3 O! h" \) Y: O7 G& K
### 示例代码3 N, s) ^1 F; l, C& o

3 I# G. K6 c% m% E) `+ q) H, V```python
3 l7 E' Y  @7 l* _+ @: \3 Q9 ^def floyd_warshall(graph):
5 J* S5 t9 S( E3 k) z) w% l: l6 E    # 初始化距离矩阵7 ]8 c) I9 x/ [0 w8 U  y' Q
    nodes = list(graph.keys())$ I. f4 j, c" z" G, S
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}
3 x$ p( e6 z7 b3 @# Q% D, ~) C. r. L& u* h' k+ S( ~
    for u in nodes:
0 I$ m% i. Z8 c  U* K( {* V5 A2 V5 x        distances[u][u] = 05 F' [* Y, @9 b5 T0 u: `
        for v, weight in graph[u].items():1 r% s: T7 f/ @6 u+ w
            distances[u][v] = weight/ ~$ G2 @/ X2 Z% S; \
4 ]% E; c0 P8 K6 r8 y% A7 z7 x, j
    # 更新路径
5 ]  z" H3 U  k" \9 d3 T! L    for k in nodes:
; }$ y* l& A6 _( G) @8 M# _3 \        for i in nodes:
& r* v8 N; p( r9 G5 _            for j in nodes:$ o& F: |6 N* R& D. @/ @2 L7 P
                if distances[i][j] > distances[i][k] + distances[k][j]:
) M8 \! `, f* g" a& r% |3 G) W0 M7 W9 E                    distances[i][j] = distances[i][k] + distances[k][j]+ S1 H) A( a5 I9 ?

$ T1 h- m9 I4 d3 `5 q  \    return distances; }- F  e$ V- L6 \

) z! J6 g" o0 v# 示例图(可以含负权边)
; F- i' r7 S" y# W- {graph_for_floyd = {4 r9 @+ R& ~, T, w8 j) f
    'A': {'B': 3, 'C': 8, 'D': -4},
) E& S% _- ?" ~0 L    'B': {'C': 1, 'D': 7},+ A: g$ s: e& x+ M% n7 l8 e6 x5 r
    'C': {'B': 4},
, W9 a3 s/ s; q/ V( `    'D': {'A': 2, 'C': -5}
, a6 e' T' H2 T& ?# a* [}8 V; K) |& ~6 R

: A' S) m, B: d4 h7 @. d7 Dshortest_paths_matrix = floyd_warshall(graph_for_floyd)7 V: H6 @  y3 ?8 y: s0 n# O
for row in shortest_paths_matrix.items():. P8 e, d' y! ~. X7 z
    print(row)* L' i: d! I8 {) l. @
```) O6 v6 O" b- K

' y7 a) J  X  y0 o' Q/ `+ p## 总结
0 G0 F" G/ o" s4 V6 q$ B7 W2 t2 s
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
' J8 `8 ~5 j* j- M! [- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。2 c$ ?6 a" Y1 A; s! U( [
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。
+ j7 I/ e" ]* y! j2 y7 Y+ D" \; M. i/ ]) K+ ?( I! D
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!
! E/ A# t& w: {: m% u2 j3 W. \
" G) s0 `) U4 V# Q6 l8 K8 z# ~3 g7 t+ F; B3 W, C$ P

' e1 X2 g& Q/ B4 F

最短路径算法Python代码.docx

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

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






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