数学建模社区-数学中国

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

作者: 2744557306    时间: 2025-1-13 17:26
标题: 最短路径算法Python代码
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。. A9 k9 ?/ s9 T9 @6 E
6 Y3 X* e2 X5 x
## 1. Dijkstra 算法
9 T2 D7 H( \! d% u# ^5 l, F& Y+ f, J, H
9 p( Y: a5 y% o0 R/ n4 d& M! nDijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。
# `- b2 K) D  z
, ^0 _2 P9 O0 M4 J9 K% @### 原理步骤
& u7 O3 {1 B% R9 L2 Q; |: T( V8 j. o8 x
1. **初始化**:5 p' e3 a  {" M) f! P% V
   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。
! ^/ n* R( X8 G$ h   - 初始化一个空的优先队列,用于存储待处理的节点。
, z9 F: z% ?- Y1 k5 x* Q6 n9 y) u
2. **处理节点**:9 p$ q6 x7 [" j' b
   - 从优先队列中选取距离最小的节点作为当前节点。
) b, h1 ^4 l8 ]( B   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。% i! G7 v2 U6 g3 p0 ?3 X; `6 E  ^6 a
5 Y# f; B9 t  L# O
3. **重复处理**:8 K$ U  \( i: a  a3 I0 l
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。
' s0 e8 L" ~) V  f3 n  f
! V  L' y8 n# \+ I' X### 示例代码5 K% R) f7 C/ T8 r
4 N  v" |, s- S. x9 X5 E6 N4 r
```python
5 C6 L/ j+ G3 f* _4 ]- u1 Timport heapq
$ }0 \+ A8 v' D" i% s! `% H/ _: O4 X% j3 x, |& t
def dijkstra(graph, start):
) [: g5 F$ w3 L! M8 ?# _8 T    # 图的表示为字典,键为节点,值为邻接节点及其边权
7 z4 {# }! A) [    queue = []
4 w% N1 I% J% M! M5 p7 S    distances = {node: float('inf') for node in graph}
" P" I5 s0 G3 z3 |1 T) `" W0 R9 B    distances[start] = 0
& N* K4 X6 p- v' H( |    heapq.heappush(queue, (0, start))  # (距离, 节点)
- d( A4 L' U, h  ~0 [2 S; N' h: {7 Y+ R& ^; d
    while queue:7 u! a2 |% V  c, H8 X
        current_distance, current_node = heapq.heappop(queue)
! M/ M2 i1 j" h. G3 T0 L0 N7 s( F0 V# \* [8 o: h* T
        # 只处理当前节点的最短距离
3 M+ H# L! ^- m! ]( C3 E        if current_distance > distances[current_node]:9 C) z1 t3 c1 v* c" z% D
            continue' P0 u- L3 c0 H
, n$ i; b, n, U$ K  S
        for neighbor, weight in graph[current_node].items():
. N* [8 A9 ?8 c" N# U( Z# o            distance = current_distance + weight: g9 H2 L# O/ T  E; d

6 g- w! _1 }$ n) q* J7 z            # 更新邻接节点的距离0 [( B" b, o4 H
            if distance < distances[neighbor]:& V9 R8 b6 |$ S1 ?
                distances[neighbor] = distance. r* }2 y0 s! R$ o0 G( X, d
                heapq.heappush(queue, (distance, neighbor)). D9 Z$ j/ {) l1 N3 P9 v

) s* a) h3 Q% s* q# ]( o1 v    return distances
8 |% F8 n2 K. c# Y5 R1 ?( E1 e  H) G. U( o
# 示例图
# K, a/ Z* S$ B3 ?7 Ngraph = {
( p1 ?; Y# {9 z" K8 L    'A': {'B': 1, 'C': 4},/ \) {% D1 X. {: l8 l, w
    'B': {'A': 1, 'C': 2, 'D': 5},
3 p+ v$ _' u! `    'C': {'A': 4, 'B': 2, 'D': 1}," c. K+ g. q9 T) b) M6 `$ \
    'D': {'B': 5, 'C': 1},
: c& T9 h/ E  A. |}  n8 z0 m7 g% |1 w

3 Y4 Z; Q' j5 L1 ~# Hstart_node = 'A'  [7 E: v9 F3 E9 T9 s) X+ `
shortest_paths = dijkstra(graph, start_node)) h9 [& Q5 I1 I; P1 x+ ~3 Y
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}# B" }* M1 c, }- w6 r7 E/ L
```& v* G$ ^8 h* r* i1 _; O% V8 s+ C- _
4 D- h- r$ j0 A; F. s! n
## 2. Bellman-Ford 算法- `  p7 _' L$ `; y) k+ P1 q1 A7 E
2 _) t. x1 k, U) c. ^! Q/ i  Q
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
3 v7 Y  l# C) }+ P+ l  @/ h6 f3 L* b$ B9 {6 q2 u
### 原理步骤/ \  r8 Y# U- R" ]9 T- K

+ L) n" Y( [+ N" P8 f% G1. **初始化**:
  D! Q5 w- G4 M- y8 X8 X. |' c   - 设置源节点到自己的距离为0,其他节点为无穷大。$ z2 v7 a9 p" W( B2 _, c4 F3 d/ }( g

- l- e8 A" P$ @5 E: [8 Q2. **松弛操作**:
; v* a5 B' A' q5 U' u2 m4 J   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。* A7 v1 K) [" _; N% I9 x# [
) ^( O( X* s, R
3. **检查负权回路**:
$ m: Q' I, X1 {* v   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
% u8 n- T: g. _( L( e& R2 R- _$ H- b- h) U7 Z# K1 p2 D) C8 K
### 示例代码  P+ I# M0 u- C# e* P. w6 `

6 j8 l5 S; `% _- z$ x```python# q4 u6 l; ~) L) A. p( C& h
def bellman_ford(graph, start):
; v4 ?/ k3 v4 w    # 初始化距离
! `& M& E8 T9 T) G    distances = {node: float('inf') for node in graph}
- x  j8 Q2 o: x; h. b9 b    distances[start] = 0$ [" [' J3 G6 ]$ L' U$ {
4 [7 W; n: s% m
    # 松弛操作' a; [6 h) d; _8 g/ r, B4 ^8 K
    for _ in range(len(graph) - 1):, E5 t) ?! z( S: l, z/ z6 E& B
        for u in graph:
. {8 h5 D/ w/ }6 _! `5 }            for v, weight in graph[u].items():; N  L& f; l* M8 x
                if distances[u] + weight < distances[v]:
7 v8 ]$ T% C" m* f) i5 n                    distances[v] = distances[u] + weight
- R- {3 N- G0 F- y& E) g
9 R  s0 c7 x; i( ?. a2 k    # 检查负权回路
9 T1 Z" \* L9 A, N: K  x    for u in graph:
) u0 r: F& |; A: {1 F        for v, weight in graph[u].items():  f; t) S+ A4 a$ V# g4 T; F
            if distances[u] + weight < distances[v]:. {/ ?$ }; p' B7 U
                raise ValueError("Graph contains a negative weight cycle")
" R9 Z9 r0 n+ Y: }  u: d  s! C& p2 ~) p" s0 B5 f
    return distances
" x& Z0 M1 y2 S7 {
: B" k2 M# N$ P" V# 示例图(带有负权边)
) P, x4 Z3 j0 l  k6 C9 ograph_with_negative_weight = {9 T  Q) l6 h; l# R: k5 [+ \$ k
    'A': {'B': 1, 'C': 4},
( o2 U1 q+ E" s: k% p9 r- R" m    'B': {'C': -3, 'D': 2},
" H1 H8 r' E: [7 B    'C': {},
! }* Y% @" o( @& E. W, O9 z    'D': {'A': -1}8 p8 B) O# w. k! _
}, ?8 I0 z: ^+ f+ g* q8 B

& @+ ~9 q, K* f# A! i+ s. qstart_node = 'A'
9 W3 ^  k# }9 ?shortest_paths = bellman_ford(graph_with_negative_weight, start_node)
0 U* ~7 t+ K5 B  f" y; L* B) Gprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
0 W) q3 ~# q# ~& I" F```
: m0 C' H0 Q: i: _$ L* {, r3 H9 c6 h
5 @5 [) N: T; t, p## 3. Floyd-Warshall 算法
+ ^- [( |" X; A: P
' \( T+ K4 ?3 N! g  B# QFloyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
! x6 G9 w  E. C) s/ O- L$ Y, u+ n( X0 j) b5 I8 I7 @
### 原理步骤
( e$ o, m0 P9 {. ?& _# y( t; B! v3 A' Q  f
1. **初始化**:: q/ s8 H$ @& _
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。9 {* f, f! \' ?! O3 n1 K3 Q0 `7 h$ u
  V% o, }, N/ t7 p  v
2. **更新路径**:
# U2 Q3 A& r0 K) p- N2 z   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。  _& E: {+ _+ C# I0 X( n

" }7 `: y& ~* U3 i3. **输出结果**:$ @7 `* [4 {% C5 k3 Q( h& \
   - 最终得到的矩阵即为每对节点之间的最短路径长度。
7 q; m! u, g4 F+ x  m
! o! n/ U9 ]' D+ I### 示例代码6 [' J' m$ s: ]/ N& s

/ y) C  g$ w5 o) Q4 F```python" S" l" t4 A  Y1 Y& }1 g1 a! f
def floyd_warshall(graph):
% k/ _$ s# h5 ~3 S, N2 T3 c    # 初始化距离矩阵# }: }) Y& E/ w- j8 H  O- q: ~
    nodes = list(graph.keys())
. D( _, j6 C! n7 Q* g. K0 r    distances = {node: {n: float('inf') for n in nodes} for node in nodes}1 k& r3 b9 y$ H9 I
4 k: Y& s- H& o, k6 R  L
    for u in nodes:
1 G  I+ ~# o9 h1 f        distances[u][u] = 0
. x9 j/ g2 m$ P        for v, weight in graph[u].items():
  e& `7 ?8 ?! c0 c2 ~. n) f            distances[u][v] = weight
& D! F. U$ h) ~- r" L" Q% x
& n. w# h( @" w" K/ O    # 更新路径
7 O- `- e/ @' F1 ^# [    for k in nodes:
  w. O" |5 E* k6 _        for i in nodes:
% [" K4 b9 m9 l2 G5 `* p            for j in nodes:
' a" c- K5 o( i: a/ W/ F- t                if distances[i][j] > distances[i][k] + distances[k][j]:
3 w" v* [2 v7 ^0 N6 M- G2 o, ^                    distances[i][j] = distances[i][k] + distances[k][j]
' P/ G2 t- r* p4 C
' y$ p) q- N" o$ I- n    return distances
6 e% p) e# D! v. Z- Q- k( J. q
# D; o( t. C: m1 S) p# 示例图(可以含负权边)
3 A! B7 ~# c( V) r6 I  o( ngraph_for_floyd = {) P6 e: ]) O& V0 W" J; v
    'A': {'B': 3, 'C': 8, 'D': -4},7 E* D1 O" e1 }& C
    'B': {'C': 1, 'D': 7},
2 {0 _$ }# F1 |' r/ M+ K. G    'C': {'B': 4},2 g8 J- q# @% U# @. K0 {' K
    'D': {'A': 2, 'C': -5}
6 |6 x4 V) o2 x}
$ W2 U/ R9 d' \3 t; [
7 f# l, O% l- d8 qshortest_paths_matrix = floyd_warshall(graph_for_floyd)
, ?, u) u' F# y5 t2 ~' S* Z. n) ?for row in shortest_paths_matrix.items():! ~& O! ^# k: j# W3 }$ {; R( z
    print(row)
* l4 F) A) i- z5 d$ S```( f- l. ^7 L& v. ^" g6 `9 G
7 c5 |8 b9 H9 \# ~1 K$ E3 i
## 总结& o* E& A/ H; E' ]4 U( _' \
! g+ Z- E& B: p7 h' E$ _7 x
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。( [. @3 e8 z1 G; ?
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。7 d8 o( p! z. R( M. m
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。. m3 t/ H: d3 h; w. |
8 F6 \+ j3 Y' d6 s2 E) D( b
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!6 U4 `, p" R( c2 b: {

1 X* j7 n; f5 }7 T
5 H: g) _% n( N
* v. C% ]0 f, `4 B" K

最短路径算法Python代码.docx

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

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






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