数学建模社区-数学中国

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

作者: 2744557306    时间: 2025-1-13 17:26
标题: 最短路径算法Python代码
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
6 \  ]; E" ~: k) S! z5 H1 j1 ^( E, ]/ [
## 1. Dijkstra 算法
  \+ z. I, u% C. {% `: R  F! M! f. G, {6 Z% F
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。. N$ q, e( E: q) x# h
! A4 r* \2 |, J' \8 d
### 原理步骤
/ c( Q# \3 Y" |" o5 n5 \) n$ K% A  ~9 q
1. **初始化**:* A# q" j! l) m; Y2 x
   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。
2 |  a" b. v1 Y1 W+ d0 |   - 初始化一个空的优先队列,用于存储待处理的节点。
, c8 R9 [, _2 P, A' _# z. i2 c' b& ~. m; }2 \
2. **处理节点**:
3 G8 U3 k, L1 E   - 从优先队列中选取距离最小的节点作为当前节点。
% h0 r6 Y$ I2 }   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。1 G; C0 q  Q1 e
2 e' V9 d5 `! R3 `6 D
3. **重复处理**:
: w6 M+ r' ?3 l& j1 O4 j   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。: U& P; P  J% L! e& d
) T: U( ?0 y9 y9 g8 O  o
### 示例代码
* }9 ]4 Q$ [( q9 X4 o. U0 b$ g8 q3 @! h. ?) c
```python6 u% `1 z1 Q5 p/ m0 h( f1 ]
import heapq" U$ r" x% W* O. l

: }7 }/ k  b- F/ c" x; V0 Bdef dijkstra(graph, start):3 T2 S' M9 s- ~2 Z
    # 图的表示为字典,键为节点,值为邻接节点及其边权
2 U7 P2 f- H2 c$ j! U    queue = []
* g+ f0 Z: ?' I; z6 Y  [. S    distances = {node: float('inf') for node in graph}
" R' p! L5 c$ B8 z    distances[start] = 0
) }) r5 f9 T- l    heapq.heappush(queue, (0, start))  # (距离, 节点)9 F4 r6 Y& l' l1 v7 |, u8 n& V

4 D3 [2 F5 F2 p4 ^9 d    while queue:
& e6 ?5 l3 I0 j8 d' ^* _3 v0 b        current_distance, current_node = heapq.heappop(queue)
7 S% t# g$ I$ E* D" {- C# ]8 I/ Q8 j& f: ~% }- p4 h
        # 只处理当前节点的最短距离
' C$ Z2 y1 V+ A9 s        if current_distance > distances[current_node]:# I: Z0 E' a* C8 D# L8 z
            continue* e- @1 ~# |/ J9 _; N7 h; q2 M

2 e+ i* a, Y" c. c; W' e        for neighbor, weight in graph[current_node].items():4 ^1 K/ z7 \: i
            distance = current_distance + weight
6 }% z" C9 K7 {, ?* e: c8 e
# f' Y: G1 l; |' {4 U7 }6 B6 O$ Z* N: n# ?            # 更新邻接节点的距离
$ x9 V/ e! d. `            if distance < distances[neighbor]:
2 }2 A/ A' w) P( z9 G& X7 i* |                distances[neighbor] = distance( k8 L4 C6 z( c7 a- u- I
                heapq.heappush(queue, (distance, neighbor))
; o' R/ F3 h" Q. U& P* j& y( j9 ?! x
/ @& K8 J$ u+ ?3 u/ p    return distances; [0 L: m5 x' v" d5 m; J

/ n# t) c) c7 O8 \+ k  @# 示例图
, t( O0 [* F) \& K6 ~graph = {
$ O; {4 E0 }, \, [! V7 v2 \    'A': {'B': 1, 'C': 4},: b% a2 r' I$ q. L5 Z
    'B': {'A': 1, 'C': 2, 'D': 5},
2 X- }* a8 D/ P7 o/ \    'C': {'A': 4, 'B': 2, 'D': 1},9 Z6 ?; |7 l9 e. \# z* E. z- P
    'D': {'B': 5, 'C': 1},
' e& G4 |( l" s, j4 \9 r4 j}; L3 r9 h# `$ A' I- g. r. K0 n

( }3 |0 B. U; D% O0 [1 k, i- G. }start_node = 'A'( Z( I$ Y$ U8 d( I7 X
shortest_paths = dijkstra(graph, start_node)
! r% h& W" A+ d5 i/ z. P) Vprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}( v. z5 i! ~2 D- H% S1 H' ~# e
```$ {/ q- G8 w: J6 o% O$ N/ |2 T
$ K9 g/ L. I7 Q! p" [4 ~
## 2. Bellman-Ford 算法. g- e# m) e  z9 _! \
5 @- G0 W* o& d% G: S/ m
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。; F, I) r8 k1 q9 F0 U. B2 ^

" |8 Q* l. L5 I2 C9 s" a9 [### 原理步骤
6 B' v. V) `2 n0 V& E/ a" u9 d' P+ `2 O. ?  {3 h' M% F- V# a4 ]
1. **初始化**:$ V% C2 e: ~# E& _( f8 i
   - 设置源节点到自己的距离为0,其他节点为无穷大。
3 w4 _" T! L3 ]
" }8 E- F$ I0 p- j2. **松弛操作**:
1 ?. H4 s; d5 _# y- K/ m2 O   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
0 t1 I# l" o* C* t" I) @
  F& U9 q5 T$ E$ t3. **检查负权回路**:
* {3 `; `- F) ]1 r$ W5 @   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。( y# |& N; K# {- Q" n1 K5 g
8 i4 @; |) f! n; i
### 示例代码
, W& n' l  W2 ^4 k, T2 x: `1 a* r2 q( J5 O3 _! d
```python
: j2 H! k6 @; d- ndef bellman_ford(graph, start):
7 w; d: A0 X9 z$ z! q% {* u% ~    # 初始化距离
: m$ g& d: x- {* g- `: J    distances = {node: float('inf') for node in graph}
1 k7 M8 n. Q7 G' {$ q    distances[start] = 0
) d' X: {) [1 X- D6 o1 R, }, U& \$ \+ C3 |( [- C# Q: C
    # 松弛操作
! _- F% @6 U) U    for _ in range(len(graph) - 1):
. G& D2 ]; K: o; Q        for u in graph:8 S" D1 }# ?: P4 T( y2 C
            for v, weight in graph[u].items():
, y# C' E8 |$ a9 L) Q; s" z% f                if distances[u] + weight < distances[v]:
1 A% E  [4 s0 O! t5 @7 d& v4 d                    distances[v] = distances[u] + weight$ X( d& Y* Q; k8 D7 ~9 r9 X8 y
2 H9 ~) r( m& \- m0 K
    # 检查负权回路% E6 m2 N& P+ r. U
    for u in graph:  l8 f* ~1 i. E& r" b% Y8 w
        for v, weight in graph[u].items():
8 @3 R+ S+ o# f" U: [9 \- Z* g& N            if distances[u] + weight < distances[v]:+ k1 L  T0 n: L4 f1 H& l0 J3 G% v( _
                raise ValueError("Graph contains a negative weight cycle"); U0 z6 c: I( R$ H1 J3 I, \

) e. r* L- B3 t/ H) ?    return distances
  c' ^- u: ]6 }- l+ t* M/ z3 |4 J  I- Z9 R8 w* }4 R
# 示例图(带有负权边)2 K' E( M/ `  \: |/ }$ S
graph_with_negative_weight = {+ n) D& i- D' y5 s/ Y* D- {: }
    'A': {'B': 1, 'C': 4}," B0 r: c% _* ~9 y. T' L
    'B': {'C': -3, 'D': 2},: n0 P" M! o) d. n$ W5 R. V3 w
    'C': {},9 n; H. x" X# U, X
    'D': {'A': -1}
& a9 O0 \2 L9 X, k2 ]& a}
5 Y  j; d: S: K9 t3 x$ k
+ E0 `) ~/ j2 v) n- B! i0 _) dstart_node = 'A'
, H. f* y( W; w- W4 c3 |shortest_paths = bellman_ford(graph_with_negative_weight, start_node)
5 `) e, ], r$ _1 d8 xprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
* W' c$ G4 Q9 P7 Z5 P```. ^# D8 ~* @0 Z* j  @
" H: \9 _( [* s, B6 R! ~5 x5 X
## 3. Floyd-Warshall 算法
# O% _* u1 O# c) e/ y! n
" H# C( v, K5 A/ sFloyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
: \! {" t+ D% `" |
( }. U2 Q4 o* g% F) c& Q1 x### 原理步骤
& I. r. Z$ w! j. Y1 d6 J- |3 i8 f$ R# Z- G2 Q
1. **初始化**:/ a8 U4 c8 K2 k8 W% {7 A
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。
  t% d. F# k& S' z; D' A" e; ?- _9 a% j' |$ d, s2 z! R
2. **更新路径**:
5 H& D8 y, I! g- e/ d$ y' Q( a0 l   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
' w0 b! l( O4 w: p9 z* _2 N0 `
" u. D* p4 @; P, N: w! P3. **输出结果**:
) V! j, ~( B3 ~5 V( ~' b6 O, K   - 最终得到的矩阵即为每对节点之间的最短路径长度。
( X8 |- H) O! \# ^+ h
) F4 j  O6 B: k0 z' s# Q( _* k### 示例代码
! A* i5 _- r* ~+ I, L/ [" g
3 u. D, |- r! t; _1 h" z1 J( S```python
% H6 ?7 ?# I& ]: B4 @9 ]def floyd_warshall(graph):" X* l& p* u* _2 ~0 p+ l
    # 初始化距离矩阵9 i4 U, q; I2 m6 {( Q
    nodes = list(graph.keys())
' ~* f; i9 A9 J( ^9 u9 D    distances = {node: {n: float('inf') for n in nodes} for node in nodes}
4 s6 `; B$ a+ H0 E; P  O( i- T& R, ?) t+ v6 o3 F3 C
    for u in nodes:4 z7 j& p$ m) T6 O: C1 c
        distances[u][u] = 0
0 D6 _. e. q3 _6 Q  q3 y0 y        for v, weight in graph[u].items():& {3 d+ B3 b% g$ ^, F" m5 ^
            distances[u][v] = weight9 U) c, L: ?# ~) l* K/ K

2 Y: [6 t/ W; G& R" _; T    # 更新路径
! Z5 q" S# E( g4 W) V: F    for k in nodes:! K4 K7 C; S+ v  A
        for i in nodes:! {/ n& T! r4 X; A2 }3 l( T
            for j in nodes:
4 j1 J- T: H1 r: e7 M, t& k                if distances[i][j] > distances[i][k] + distances[k][j]:
$ \1 N7 y9 Z# c                    distances[i][j] = distances[i][k] + distances[k][j]5 n( W: J+ ^/ m
# \* c3 ~# K2 a4 V& ^" x  p& T
    return distances0 Z' i; {! v! k- L  f6 A
# K. L9 Y# [$ m% z& x( a+ |2 P
# 示例图(可以含负权边)
+ i4 L8 m$ G! Z0 qgraph_for_floyd = {
% J% r# q8 c$ a$ {& r    'A': {'B': 3, 'C': 8, 'D': -4},0 O" W7 U% ]& d+ H' [, B
    'B': {'C': 1, 'D': 7},
5 X) c9 Y4 U1 T$ u  X9 K& q  b    'C': {'B': 4},
+ B$ I8 ?: `. v6 }9 F* @6 _8 r    'D': {'A': 2, 'C': -5}
/ ?- i8 W/ S( A4 _, e}4 ~' x3 b7 Y' B# I9 Q- W
, D6 Y4 O9 t7 h1 ^' v& A4 |6 x
shortest_paths_matrix = floyd_warshall(graph_for_floyd)/ Z) N  s0 W/ n3 s. w5 K
for row in shortest_paths_matrix.items():
* _2 t7 q/ n' h: W    print(row)
$ e$ {  b  C: P$ o```& Y$ Y: P. F' s" H$ A! v

4 ]8 W* f) g. [3 I## 总结
  U  K# L' y0 {+ W' c0 ?7 v* A/ o% H) @8 y" @" W
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。% O, z5 V6 x0 H4 ], ~
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。4 t* y; I7 ^3 [0 @* n
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。
. f1 o- D0 M; v1 r% ~) }1 ]2 \
# c- V4 }- ~9 x# ?# f不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!
$ q* g( ~6 P# O. i2 u7 K% M" E4 I+ F& V6 X
) G( l8 E, o! H5 k: p' V0 V

1 s5 b" v8 O4 q7 Z* s

最短路径算法Python代码.docx

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

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






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