数学建模社区-数学中国

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

作者: 2744557306    时间: 2025-1-13 17:26
标题: 最短路径算法Python代码
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。# F. z: ~4 ^# z1 H& q  F' O2 V
3 i0 t* C5 z2 G  C+ e
## 1. Dijkstra 算法
3 F+ D2 K5 F- ^0 F/ {; I5 M( F& b; }: z; R& d2 q0 J+ s6 ~
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。
" \) F* y: m, F' j6 B9 E) A* E, Q  T9 q
### 原理步骤
  u* \  t0 \7 O& t7 {. C1 x: d0 S; P# I" d: D+ _
1. **初始化**:/ I' ]9 z7 T3 o1 H& _; B  J4 I
   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。: Y. v  S) x. o- Y+ M
   - 初始化一个空的优先队列,用于存储待处理的节点。$ e' q) `" r% \5 l5 C: _" i1 B1 S

! M1 P8 g: N+ E8 Y5 J6 d4 Z7 M1 Y. a2. **处理节点**:( j1 g2 o' ^! w2 Q
   - 从优先队列中选取距离最小的节点作为当前节点。7 L6 P5 u$ R( ?5 y
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。0 W9 J6 Y" h" E2 c5 C! V9 W

2 Z: @; r' o2 r7 c( _# @3. **重复处理**:
: R- z9 M+ J: k" M   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。+ S# }$ n8 |1 _8 n% m( Y( s8 |

4 m; n+ l2 F! S& {: _### 示例代码1 O' f5 T1 j$ h  }) s4 C
- ~7 V; c7 w- F+ }+ k: z
```python
, q; ]& u0 X2 d' L  limport heapq
% H+ T/ ^4 m: F
8 d& i8 N' d5 g4 Y7 Idef dijkstra(graph, start):
. z) B( P- l3 M! w. @2 K    # 图的表示为字典,键为节点,值为邻接节点及其边权
/ j% e1 X8 N8 q5 j7 a    queue = []- Y% ]3 j0 F# u0 i8 p- ?! M
    distances = {node: float('inf') for node in graph}& J( a7 v; m/ ~6 }" d0 D3 l
    distances[start] = 0% x' w; n& ]& ~" H
    heapq.heappush(queue, (0, start))  # (距离, 节点)
2 T% F$ c5 H0 Z" H5 y! v! [* ?8 H* B5 l9 Y4 p" \
    while queue:6 q6 H. [) I4 A, F+ K. ?7 v) L3 G
        current_distance, current_node = heapq.heappop(queue)
, t4 a5 o6 {9 D- }7 ~$ `! E7 M6 S6 l1 j
        # 只处理当前节点的最短距离
7 N' A# Z/ F  w+ A  C+ Q! c$ N4 Q        if current_distance > distances[current_node]:: M0 K% Y9 c" V; k& A
            continue& a! F; Y' A8 Y# q3 M
3 M" n2 t$ H" Q! F9 s
        for neighbor, weight in graph[current_node].items():
/ i, d5 w" P$ Q* Q( s3 I' V            distance = current_distance + weight- C. W% v' f5 p# S9 L- ]( z

' E, E4 N. H; e0 Y            # 更新邻接节点的距离4 _1 @2 ^+ |, B% s+ n. I
            if distance < distances[neighbor]:$ \( C; F( t( a% B
                distances[neighbor] = distance& x6 e; Z8 P8 u1 T( I5 d
                heapq.heappush(queue, (distance, neighbor))' j( f2 o% E9 V# u" j0 V* D

# G/ P. Z' T6 K: I    return distances
+ z! r* a! N( z  f) v% m; H% E: g5 c/ w
# 示例图4 `" q( }. K! u
graph = {% t9 _' r  A/ P* r1 @
    'A': {'B': 1, 'C': 4},, K; N+ R- z# @9 E: s) O
    'B': {'A': 1, 'C': 2, 'D': 5},
1 A/ D5 n1 v/ f    'C': {'A': 4, 'B': 2, 'D': 1},; D1 p% Z1 f. Q* C! v# S4 b) y
    'D': {'B': 5, 'C': 1},7 q9 Z' ?( `6 }6 c- ~0 ?4 Q
}2 F, W+ d$ w3 U% l1 t5 W
- m2 T# r5 [6 O
start_node = 'A'
$ W( u# ^+ X0 o' P: _shortest_paths = dijkstra(graph, start_node), x/ Q, R2 I; K  k. [7 f
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
5 x- y$ [7 W8 `8 D```  r2 H* ~" S3 B% D) s, O

+ o. Q1 L$ t: l7 \6 _+ j## 2. Bellman-Ford 算法" n; A! Z) C  u

7 P! z3 }0 H* T  MBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
0 ~1 W8 E, |" D0 K; l+ N* Z
1 Z+ o# ]- b8 `; u( b- Q1 Y### 原理步骤
' t' H6 b' |0 N& ]0 `
0 Y5 Q1 E( U5 f1. **初始化**:- ]  t7 f) w8 [) f! w
   - 设置源节点到自己的距离为0,其他节点为无穷大。' N4 p9 z) \9 ]

5 D( M9 ~/ Q  c4 ?. F9 F7 ^" H2. **松弛操作**:* ^* q1 p3 [1 `
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
  g7 H1 n: [' U2 e" Q$ K) G% e" Q3 W% r
3. **检查负权回路**:7 \0 ?4 Y& k! S: k
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
* _4 A+ G4 `& n3 Q* [
$ p( t0 {5 `/ T. @5 E3 ]### 示例代码
6 }' Q$ Y0 ~2 a. S; T0 r0 g! I
6 @; N7 }: M( [- o6 v3 }6 _7 ~```python# D" [8 l9 H. ~2 M% C
def bellman_ford(graph, start):' N. {+ ?! T& P- ^3 s3 o3 ]
    # 初始化距离
- N0 S3 N  q' ?- U    distances = {node: float('inf') for node in graph}: p* J6 F) F1 {
    distances[start] = 0
5 R) I" G% c% W# o7 G
# B, s( w' f; k/ G) \    # 松弛操作% C" e3 \* P7 p7 |( u/ F% \- f
    for _ in range(len(graph) - 1):
5 W# h& i* K# S1 H" [        for u in graph:* e) ~( A. M, ^& j1 a4 P: v
            for v, weight in graph[u].items():' E9 {) d2 N7 G
                if distances[u] + weight < distances[v]:
- V# @7 ^, h+ w6 r# Q- d9 k- m% h, [                    distances[v] = distances[u] + weight
7 y# e+ P( b( k# [. o; N& z5 I$ G+ C9 u7 A8 c9 l1 C
    # 检查负权回路! r9 p3 c9 G& ?' L4 k; D3 e1 p  k% O
    for u in graph:+ }- n: K; Y: e- F
        for v, weight in graph[u].items():
$ `: Q; t, v  ]9 X: t7 x0 i            if distances[u] + weight < distances[v]:/ d/ x$ G! U( n( |9 C
                raise ValueError("Graph contains a negative weight cycle")2 ^6 ^. E: x6 j; f/ f0 f$ S

( U7 f& j6 k+ Q  s: h- t# j" ?    return distances, p$ y& P6 E# k* @

# ^" _7 h( }4 W9 o+ y' a4 o# 示例图(带有负权边)
# G/ Y. a7 s* X' C5 ggraph_with_negative_weight = {
$ r; b, I+ T- `0 Y! ?6 V/ U: u    'A': {'B': 1, 'C': 4},
- @$ B2 h0 h9 {0 P    'B': {'C': -3, 'D': 2},* O  V: R/ r! T9 u8 W9 O% K
    'C': {},  J" k" H; Y3 n  W
    'D': {'A': -1}
) U' r$ V, Q, a" ~+ W/ H}
+ i* h% W! S4 v4 |  |: l# ~2 p7 n7 v1 [  _/ U4 p. v
start_node = 'A'
$ R6 M  @! E( ashortest_paths = bellman_ford(graph_with_negative_weight, start_node)/ x* a/ `9 c: n' _0 {3 i
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
+ a4 \+ V' A: p" l  q```
# m0 J0 C* e; L8 ?6 N7 s2 _7 }3 c- V  j- ]
## 3. Floyd-Warshall 算法) t+ }9 ~1 l5 U$ _2 ?# X
& \: u- x1 x; p( G4 u
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。( e( t- ~! ^! R6 D( `8 a, S

) |7 k! l; Z& w8 ?0 i7 ?8 K% _### 原理步骤* N0 A7 P( j# x* |& f- A

4 F& b: O5 F  O7 J1. **初始化**:
+ Q3 k2 ^8 |5 F5 Q   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。" ]# ]4 r7 T7 k  `- C2 G) w( i
& B3 [" V& i# g! [5 Z! [
2. **更新路径**:' F: S0 W5 u' Z
   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
$ I) u3 C4 A$ M/ Y. k; U+ ]- O6 y) g: p' i# C. P) k1 Y9 [. {# t! C
3. **输出结果**:' ^( v" Y6 L" s7 S+ G( ]$ S
   - 最终得到的矩阵即为每对节点之间的最短路径长度。
9 Q: t7 O+ _5 S) W2 K) a7 [4 l( N
! g$ \6 E9 a6 V  F, F4 b$ K! m* n+ @### 示例代码
% L# [. q" J- d# Q( \
  w/ k: f# r. O7 J' m8 Z& U( {```python
9 X/ q! ]- D& ~1 W" d- jdef floyd_warshall(graph):- s! q. d/ f- E- D7 U
    # 初始化距离矩阵
; C8 ]- N/ L; K* K7 \/ O    nodes = list(graph.keys())- E: v& \9 y$ l/ W% ^
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}1 p& E6 m# Q) [2 w

6 G% w7 E3 i7 M) v( l    for u in nodes:$ L1 g# g& G! \" A
        distances[u][u] = 0
& k; _- q( g  M% W; F        for v, weight in graph[u].items():
# ]! I" v: R( b; F            distances[u][v] = weight
5 N8 H4 ~/ s: T+ M' q
! r# g4 ^! O! c* O) X* G    # 更新路径
' t7 }' `& U2 E, \7 j, ~    for k in nodes:2 P) n! x) q; V) r, W9 M. z$ }
        for i in nodes:
+ G6 z" O- j0 r/ T            for j in nodes:
  i+ S3 W* A& g9 y! H                if distances[i][j] > distances[i][k] + distances[k][j]:
% R, N% c1 d9 L+ i4 T                    distances[i][j] = distances[i][k] + distances[k][j]
3 t) u. v- R9 a- M  c
, Q$ f: L4 Y$ ~# \: o    return distances- [: y) ]) I$ y
8 q5 t& t& p, ^) B
# 示例图(可以含负权边)# S) c3 {5 S0 a
graph_for_floyd = {7 s! ^9 L% |. z( r6 w
    'A': {'B': 3, 'C': 8, 'D': -4},7 p7 U7 U$ g  j; [$ Z) V
    'B': {'C': 1, 'D': 7},
+ F/ u# l" b$ L: @6 h% y1 u    'C': {'B': 4},8 {' S4 X2 w' `9 d  x
    'D': {'A': 2, 'C': -5}
5 ?2 r) l7 ^5 @$ l& ?}2 T* Z6 q* s% h$ U/ r
3 i- Z1 l; k/ |! x3 x( ]3 T6 g. O
shortest_paths_matrix = floyd_warshall(graph_for_floyd)+ }+ t0 o, {+ o6 H2 }4 {
for row in shortest_paths_matrix.items():  g+ m5 X. M5 e7 a. ?2 Q
    print(row)! O% M- \) a- Y# w' [: a
```
' G* G' \- e1 D- `  X  h0 T  q4 U/ l5 m! r- _& @, v- ]  ?
## 总结9 p! I2 T' n' t8 C( ?

: e2 E+ x& O. |. T7 O* t9 S4 e: o- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。2 [/ r7 K8 t& ^. j' @
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。7 X5 V' N4 E: W4 x+ P6 _
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。; c& M( `, {* \) s* q( P7 e
* t2 u! A: E6 W! i. d( ]7 h
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!$ Y# _! R9 w6 \" l' D

$ ^6 D8 K/ f( d' t  D% H  f
4 l$ ]1 Y2 w; C7 k$ C2 F2 `- p+ V3 A5 J! \7 S

最短路径算法Python代码.docx

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

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






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