数学建模社区-数学中国

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

作者: 2744557306    时间: 2025-1-13 17:26
标题: 最短路径算法Python代码
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
2 w1 Q* c  X3 z1 _- z" i/ I/ O8 ]. A3 u3 ?5 K1 s5 E1 U& M. ]5 H
## 1. Dijkstra 算法
1 Z1 \- `1 o# u# _' v2 m6 M3 u2 d; B4 @( ?8 s/ }. q
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。+ @" v- d0 q" C& Q1 v- N! C/ t
) o7 Q5 F6 X- O3 H7 G% x- I
### 原理步骤
5 J9 a, j$ J, T( l5 R9 s# ^. u
8 k5 V% W* I3 u% w% A0 v# m/ k1. **初始化**:
! N: K9 X) t! ^2 j   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。( \+ R, {$ x5 y& ?
   - 初始化一个空的优先队列,用于存储待处理的节点。
7 Y6 j# r$ ~% K+ x0 @4 S4 B7 {$ H8 u9 y5 R+ c4 h  E; K2 h
2. **处理节点**:+ A9 b) L2 u' B9 V, ^9 ?
   - 从优先队列中选取距离最小的节点作为当前节点。4 |% U. F" {0 i) ^+ ~' d. T' ]
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
" @/ |# {9 S8 U# A) y$ _( p
9 @9 i' y6 t" \& s4 E3. **重复处理**:
% R' a! \# j, x4 s* X" Q   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。
  \0 j0 g  M. a+ l1 A, a# C3 f1 M& A$ @, @1 K
### 示例代码
  [# _3 W1 y) @& g7 ?
- Q6 N4 S6 U/ J( ]" C( e  h: ````python, W' t% g3 s4 X" H$ X  j
import heapq" M1 d8 V: b9 t3 A/ w

" g$ @/ ~6 [6 f4 A9 O7 W- hdef dijkstra(graph, start):
: |+ A1 B( m5 _    # 图的表示为字典,键为节点,值为邻接节点及其边权
3 E5 p0 A! x/ o1 N! U0 t( Q4 C    queue = []
; N' L1 d+ v% `7 F    distances = {node: float('inf') for node in graph}
) A" r' x: P' d/ e) }2 h    distances[start] = 0
4 F) q- ^) V7 c# p1 K- g" Q- S2 B; V7 a    heapq.heappush(queue, (0, start))  # (距离, 节点)
8 C. j+ H7 ~1 i2 e% B! n/ v: o9 o
8 I3 `' m7 ~  T6 a% Y4 V- Z. g    while queue:) _6 z8 s1 E6 l# |  o3 n# E! W
        current_distance, current_node = heapq.heappop(queue)
2 T* Q$ k% ?# K* u& a' T) p9 Z. Y0 i% V/ a. k+ u
        # 只处理当前节点的最短距离% Y4 @, _# ~( I' {, I
        if current_distance > distances[current_node]:7 @9 N, {- n: Q
            continue
/ e1 m/ D, ]. n  j! ^, D7 Q. G% m) |! `2 i( A7 y' H
        for neighbor, weight in graph[current_node].items():+ a2 i, V& C3 b! @" I$ ^
            distance = current_distance + weight
* U$ T  B) K) @8 }3 ?
( z, Z1 |* g; F( _            # 更新邻接节点的距离! b# ^: ^" e: I# q& x
            if distance < distances[neighbor]:
% D) R& k8 R/ w+ T' Y! _3 x                distances[neighbor] = distance# R3 I$ x- ^! p8 T1 m
                heapq.heappush(queue, (distance, neighbor))4 Q  L0 I" `! w, l
# e+ y/ d* E$ ~! L6 k! X8 \8 c; a
    return distances
" O0 p8 S& b- a8 H+ S. t7 l. m$ @: M
# 示例图
. W$ b. N+ h" wgraph = {0 M% R2 K5 E6 T3 c7 q+ O8 k
    'A': {'B': 1, 'C': 4},
: f7 r* G* O! ?$ f6 E    'B': {'A': 1, 'C': 2, 'D': 5},
. M: \) Q, a! o    'C': {'A': 4, 'B': 2, 'D': 1},; @2 S% i- @& |  h* b
    'D': {'B': 5, 'C': 1},6 @% P5 A; J, N) }, [, \# v% o" M% k
}! G, o+ |) V9 Y

8 }6 G0 w7 e9 N3 e8 P4 U+ nstart_node = 'A'
: y1 R+ K$ ~) [9 J( s4 X2 qshortest_paths = dijkstra(graph, start_node)
( j" t: @% \6 o/ uprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
/ ^: v4 ]! y6 y! j  Z8 P( E$ z```. Y' S% t% C; k2 W3 W# Q0 @
# ~: `4 M3 B' a5 E* b4 z% s+ \# R. F
## 2. Bellman-Ford 算法
8 T  b" |$ q3 X
. Z9 p3 N) Z! @3 yBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。( ?* Z0 Z; P; Z2 t

" m) [9 O' P7 f) J3 a; Q% R" Q7 {+ ^### 原理步骤. z8 C6 d9 M; N' l  c, K9 A; a  i

5 E3 X  ^1 m: p/ h; y' U! a  t1. **初始化**:* q' x8 P& u1 j1 x
   - 设置源节点到自己的距离为0,其他节点为无穷大。( i  V6 b! e5 B1 e

/ t% ^) _) q- Y. E0 {# Z2. **松弛操作**:1 Q$ T1 w4 \6 R: k. }9 U
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。5 ?" u+ V4 i9 y, N) ?4 t

- G) X& l4 Z. o6 q. Q: \4 T3. **检查负权回路**:
$ N; [( U6 S3 K5 s# I, g   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。; S/ U. c7 V) Y8 w: R

8 X0 `6 S) g) e, j% H) x+ w3 i### 示例代码
6 B1 C' v. D2 f9 j( u
* T5 @+ L2 m9 n9 H4 V2 B```python  a# @$ A, C- {$ C' K2 j. }8 Q
def bellman_ford(graph, start):
5 B3 v1 @( h, G1 o$ U3 a    # 初始化距离1 p& X$ h& v1 e9 s* r& ]
    distances = {node: float('inf') for node in graph}, J0 u! L! t6 v! n
    distances[start] = 0
) C4 `6 s9 [1 E% {2 R; D2 b
/ m% O' q0 f7 x7 m  r    # 松弛操作, d2 t6 D& z" g4 u2 s) B5 }# J  W
    for _ in range(len(graph) - 1):
9 W% X5 U- _4 L! U8 k# y8 z        for u in graph:
6 s/ {( V2 F6 ^. C! ^# c0 E            for v, weight in graph[u].items():
0 r  J0 \$ r2 n+ m                if distances[u] + weight < distances[v]:
1 t0 [9 G4 c/ _+ e* E" d                    distances[v] = distances[u] + weight, E: }- ~% i5 i
, m3 Q0 o; k( j) q2 W& M9 b* t
    # 检查负权回路
6 K* ]$ j) f3 ]( D9 i( [& Z% @    for u in graph:( `# Y3 m* [. ^* r4 Y7 f: l* w
        for v, weight in graph[u].items():
( f! ]  `1 m8 K4 Q, ?            if distances[u] + weight < distances[v]:
  v- U( v; E8 l% z9 I/ p' u% q  D                raise ValueError("Graph contains a negative weight cycle")
* J5 Y9 n& x. J, g) @3 j& i1 g8 y3 F' E( k  w+ `
    return distances; `. w7 z( T; o$ G' P) l  `8 V
, t- q; [7 s( A
# 示例图(带有负权边)
. `. O( [1 ^) F# qgraph_with_negative_weight = {' x- V; I0 H2 S) B$ ?
    'A': {'B': 1, 'C': 4},
. w! g2 v1 _/ G) Q) l5 `3 p    'B': {'C': -3, 'D': 2},4 F1 C5 t4 [0 N$ h7 K, s. }. |
    'C': {},8 u) ?( E$ c* M! F8 k6 _; g
    'D': {'A': -1}
" B: z4 ?) H5 M1 h2 E}5 g+ j- N' v& ~% Z& Z5 |8 `% R
' Q0 k9 b  J+ m; X9 J; o
start_node = 'A'9 P8 {2 _% f2 K, |: j; D
shortest_paths = bellman_ford(graph_with_negative_weight, start_node)
  b) j- a* H( oprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
  z  S( z$ d9 z, N```! m  }2 M4 C! O2 U% n6 }

' K: @% R/ W( _, h- W* R## 3. Floyd-Warshall 算法
; d* ?) y( w( W* E; \/ @  B8 o+ j8 e( E" T& I
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。4 T; V, t  B& [; I0 P
; w! x, ~: ~) U/ _( h$ l
### 原理步骤
) k6 Y- h! y: ^5 m. Q! x4 ~7 a$ W+ O2 H$ [* z3 P* g, K! p
1. **初始化**:6 Y& M9 P& l, h$ t
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。+ y2 `0 w6 a; z( D

3 m0 c# l: m' z4 u+ x2. **更新路径**:
! Y5 A3 h* U0 \/ T   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。1 O2 r1 D% U' i  D

0 X: C- D* @  ]3 o* m3. **输出结果**:
! ?6 p) |" L# G1 D3 x$ M2 m   - 最终得到的矩阵即为每对节点之间的最短路径长度。
9 m% K+ A6 p3 I% B% ]" g* Z' @3 G. I; u! H) j$ f
### 示例代码
4 C3 U4 M" u9 C8 i! K# s9 |$ N$ [( F7 d+ l/ s( y2 [
```python
) v6 R* W, D  }  z# ?def floyd_warshall(graph):
- ~& c  L' j8 w; L# B, t/ k. u# h    # 初始化距离矩阵# z+ i- C: R" f- I' y
    nodes = list(graph.keys())8 f4 z" c# K5 V
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}3 f8 C- Z8 V) [  ~( T
1 J0 ?( x+ J" i/ R
    for u in nodes:
- J0 [$ |; Z1 U" D        distances[u][u] = 0
; o# U% T& e8 d6 Z" t" C        for v, weight in graph[u].items():1 W! W) ?' h. a
            distances[u][v] = weight
8 B4 `4 C1 Z7 w& x$ w: Z+ E: B3 B6 x1 o: v
    # 更新路径  U; g% k. J. |+ t' w3 ~7 m
    for k in nodes:
, x* c( |7 k2 e% I2 W( Z- W) [        for i in nodes:
+ B. A% P! g+ J3 [  k            for j in nodes:
% q; W9 c7 n& h% A/ i$ d                if distances[i][j] > distances[i][k] + distances[k][j]:
" r3 T7 g' g/ `9 A1 x                    distances[i][j] = distances[i][k] + distances[k][j]
$ z$ H' {8 v- n
1 w6 K4 N% v. j6 w4 r    return distances5 H  ?0 w2 ~3 T: |/ K6 h$ {4 R
! y3 p& O( x/ u
# 示例图(可以含负权边)* F5 z; S: W3 n1 Y# x8 f
graph_for_floyd = {
$ |: q. }7 p8 l7 i1 O  m    'A': {'B': 3, 'C': 8, 'D': -4},% g6 P+ U, |! x5 ]9 t: x/ l
    'B': {'C': 1, 'D': 7},
  L* ~& O+ ?/ p/ n. M: F3 f    'C': {'B': 4},$ A5 x; |: t& k2 q
    'D': {'A': 2, 'C': -5}
! _$ o9 X  g5 z8 s6 x% Y  a, D}& r5 _, V8 @8 p/ R$ r* u! K4 r8 Z+ ~
5 C- \5 r7 R8 b5 c  @0 j; d2 p
shortest_paths_matrix = floyd_warshall(graph_for_floyd). w; M8 _. [8 i# \. Q3 \
for row in shortest_paths_matrix.items():, W& `/ v3 G0 `9 f
    print(row)
( l3 ^, G) T. K2 D```. e) A' o1 P3 J3 W0 x

1 M5 H' }. Y: q4 e## 总结6 Y4 I/ T; H6 @* D: L
. a9 D! D/ j- C1 [2 \$ T8 n+ n4 d
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。$ p. }  c% J' p1 e5 s
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。2 n6 b" W2 [: j
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。$ H, y0 O  _* o! ~
6 r/ r- S2 ~5 A* v  r! A
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!( _7 Y& B0 G: T# a  Q' ~
* r- Q: S7 U3 s( Z! {
; r% \8 a5 j0 @, L+ G$ q" k7 ~4 @
1 P) L% }; f! I" p8 z2 J

最短路径算法Python代码.docx

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

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






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