QQ登录

只需要一步,快速开始

 注册地址  找回密码
查看: 834|回复: 0
打印 上一主题 下一主题

最短路径算法Python代码

[复制链接]
字体大小: 正常 放大

1171

主题

4

听众

2781

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
4 Z& J5 a" }+ {3 p8 ^) t% \8 j
## 1. Dijkstra 算法
) _: B' e) [  l% Y. J7 R
! h9 Y7 E5 ?2 N# C* Z: R8 A+ d% kDijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。- L$ E9 }/ k& u9 i2 i+ K9 \* c
! R, E1 r# c. J& r  e+ s
### 原理步骤
* {  R' c  Y/ a7 S- y% x' G2 f5 _  l$ ?: O) D8 H2 p
1. **初始化**:+ v; m$ _# @% i' B$ u' ]% S; r
   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。/ S0 Q- k2 t; d/ Z; ~+ z, P
   - 初始化一个空的优先队列,用于存储待处理的节点。
6 W% G/ L$ C* w; P9 S
' N  ]% b1 I% L% Q. h. D) b2. **处理节点**:
8 E- d5 J! e; c2 _   - 从优先队列中选取距离最小的节点作为当前节点。# [3 h9 P9 A4 s; _  Q: ?- B
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。) w; S! [* ^9 `$ d! a1 z) ]

6 @2 |, \- I) Z- Z5 c9 J; j5 H/ w3. **重复处理**:
9 R% w/ w) i( D* l' a6 L* _   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。6 a& i  \$ J+ @" x) U

3 r! d! l+ S. `### 示例代码$ v* E9 h0 x7 X
, k$ b7 {9 ~! O1 N% `3 D
```python
# n' Y: `$ X5 J0 Y/ w& X  vimport heapq
1 B: r' M7 Z# Y# ]+ X; l' A0 u5 J5 p
def dijkstra(graph, start):
6 H% Q- \/ P8 p7 s+ P: R    # 图的表示为字典,键为节点,值为邻接节点及其边权
5 g. v: s# I0 R( D$ D$ Z7 O+ h    queue = []8 r" c& |9 Z0 u7 s( L( k( ^
    distances = {node: float('inf') for node in graph}; t; `# f% i: ~2 E4 P
    distances[start] = 0
2 @. h6 u" `; }  a" `9 z    heapq.heappush(queue, (0, start))  # (距离, 节点)
- h+ N, R/ k+ d# {6 a8 Y7 K$ W4 F: }( {& A
    while queue:, p) P; r$ |" ?; y. i( B$ ?" j
        current_distance, current_node = heapq.heappop(queue), O4 y7 i; M* ?( ?# e. p3 |( c* g
1 Z) G  \  _% x* g% x
        # 只处理当前节点的最短距离
7 H- |: \- S2 c. s# c0 ~% G        if current_distance > distances[current_node]:8 a0 s4 b" z4 ?$ L& G! X
            continue
- w# S8 \5 y1 i% \4 A
. p9 ?$ S9 e% ]) s        for neighbor, weight in graph[current_node].items():
* \$ o, ?+ d3 R. w" r0 y6 v            distance = current_distance + weight
6 J- c  \) N% j- Z0 ~4 m' R/ I1 ]
8 a! u; A3 g/ s5 V7 w            # 更新邻接节点的距离4 C% l# j0 y$ A+ y
            if distance < distances[neighbor]:
% a; L, X2 Z) J, i0 d                distances[neighbor] = distance( r; a$ |! e- `* H
                heapq.heappush(queue, (distance, neighbor))
0 I3 _1 J) V( @3 N' n/ `
7 D' @; {7 ]3 ^+ h- E- r. o    return distances
+ t7 N0 L+ h, z: _4 _" w+ Z  N% k2 _* h: P' \) @
# 示例图  s/ F9 D) R8 s% q  Z" ?
graph = {. D4 J5 n, n  t+ O! y
    'A': {'B': 1, 'C': 4},
* H: P  j# g/ g( d    'B': {'A': 1, 'C': 2, 'D': 5},& x/ T' h* P9 O2 g* U, w& ^
    'C': {'A': 4, 'B': 2, 'D': 1},
% y$ R+ W1 U% L( o1 N! J    'D': {'B': 5, 'C': 1},4 ?" ?8 Q) m0 q' O" F" h' m
}6 o  R& W6 t- `  {4 Q, d# b* g5 h
: L' s0 X9 E, \+ ]7 \' G
start_node = 'A'
* J! c# I4 T1 x8 Q; }/ r8 Tshortest_paths = dijkstra(graph, start_node)
) ]6 F- [; }) U" `, Uprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}/ @  y+ g- }7 G8 r2 E
```" @$ h5 H8 E5 O- Z% h8 t' Z/ n) d
. s9 x+ h9 h: T+ e1 E- c9 \' K- _
## 2. Bellman-Ford 算法5 ]! q* R( }7 d0 F! L9 b

% v0 @5 w4 X. {2 C9 `* U0 x- T# b: GBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。8 d9 y) d+ l* O* b

+ O9 q/ ?4 I* Q; y+ d### 原理步骤
" |, E1 P7 I1 }9 P0 q! ^$ K
$ Y/ y0 i5 B& s! ]8 `1. **初始化**:3 F( K+ P% c: e# l4 M
   - 设置源节点到自己的距离为0,其他节点为无穷大。
, G" m, J3 v5 J6 k; p1 C. o2 {& @1 c3 o5 h# X: L% _
2. **松弛操作**:
  O0 d2 T+ Q- d   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。) u: H, ?$ z) F: Y2 @
* T, }- a: Y& e4 j
3. **检查负权回路**:
, j! O" a( k$ P) q  T; b   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
3 f# O3 V( w6 @! B4 E; J; B" z/ m5 ?1 G6 N) e, L1 Q
### 示例代码' c6 I* a7 H8 e3 V
8 c& S  y% C; w3 E
```python
% I: V! n9 l* L% i' S2 L5 y6 wdef bellman_ford(graph, start):
& C# r3 X7 K; h# U    # 初始化距离
, g5 H6 ?2 K, X6 E7 q* k4 V$ g    distances = {node: float('inf') for node in graph}, c' C4 p7 o3 U: h) I
    distances[start] = 0
* u) I0 E: V2 `8 W: @, N( F/ A9 j/ `( U5 K9 e0 S
    # 松弛操作
. w$ [# U: y( M    for _ in range(len(graph) - 1):
6 }+ [  ]/ u8 e8 J: F        for u in graph:
: b7 Y5 E" [. ?6 [            for v, weight in graph[u].items():
: Q$ ^# `) F  ^% f$ C: F                if distances[u] + weight < distances[v]:5 U6 ]; G5 C$ f
                    distances[v] = distances[u] + weight& J4 p$ Z5 N7 I( C/ z

3 Q2 z7 K: Y( [3 T    # 检查负权回路. s7 l* A4 W0 l' e. j8 u$ Y
    for u in graph:$ R/ Z" S# A! I! p% N, _+ U
        for v, weight in graph[u].items():7 L1 x9 l0 b/ i  `. `$ Y
            if distances[u] + weight < distances[v]:( m5 {5 ?" b- p, m. Q* d0 O; P# L
                raise ValueError("Graph contains a negative weight cycle")
4 }" @( ]* I, N" W
3 z5 W6 w7 l( g% W; o/ O0 C  E% E2 h+ f    return distances- c% M/ f5 b" I( K! s4 _

: G; a, N  h9 Y2 [+ l( M$ L1 k# 示例图(带有负权边): V$ m! t4 {; f
graph_with_negative_weight = {
  A. I& ~& k4 R3 _: }) B6 T    'A': {'B': 1, 'C': 4},7 Z) i5 B( |5 D) c
    'B': {'C': -3, 'D': 2}," M: e( t, T1 v: S7 U
    'C': {},( |" K) D$ M6 m/ W4 H& {
    'D': {'A': -1}, z9 g& x) I) `. H: \
}
: ?2 v) R+ f0 |3 A: t0 e5 f0 T* F, M+ }/ p0 k9 K
start_node = 'A'
6 F  N, v& [: r9 Y4 R# Rshortest_paths = bellman_ford(graph_with_negative_weight, start_node)3 x! S5 Q) O" Y, t) p
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}8 b' s, P5 z: \
```
" ?7 _/ Y, z1 F/ i6 {) @8 w
1 w  O6 v; M1 [- r4 v/ ^## 3. Floyd-Warshall 算法6 P* b* m  z  G5 _% v! F9 q

4 D8 I2 f/ w; V6 _. WFloyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。3 P5 ~% N  L- W- a& s
( ]/ F8 p% K7 i
### 原理步骤
# J# y' }2 z* r  u; M1 Q) e
7 F  R4 e2 H5 c# k1. **初始化**:: N2 @7 I3 N. {- {$ \  Z
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。! L9 h9 b& U# }4 U  L) \
0 v) e8 I- Z0 R/ i- O( i
2. **更新路径**:
* D% a9 P% f7 b3 T% y6 c3 x% O   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。2 F% Q/ B8 Y' K* \  ^0 Y8 e

# @. ]& Z- u2 Q2 j4 w3. **输出结果**:
2 O% K. W, T7 p5 V   - 最终得到的矩阵即为每对节点之间的最短路径长度。3 M" H: Z8 V1 D' s0 S
' h/ Q& g  a9 g# _' d2 B
### 示例代码
1 ]9 {6 _) v6 U" T* B3 E: O
1 q- P: N# ~2 o; w```python
# H2 g4 m% @. }+ Cdef floyd_warshall(graph):
7 R/ g: h2 F3 }% l" k& V! v  ?    # 初始化距离矩阵
( Y8 K0 c7 c4 |. A( F    nodes = list(graph.keys())
4 e. h" n& F& J" J4 Q4 v. ]8 \3 i    distances = {node: {n: float('inf') for n in nodes} for node in nodes}
, P6 T2 G' h' e- ?) s+ {& I( p. J9 H9 }  j! R+ w' g
    for u in nodes:- I2 ^- J& ?" |; U' p5 D( ~6 Z
        distances[u][u] = 0( v8 N- R- `. d8 A7 I5 e* K/ g" x
        for v, weight in graph[u].items():& i& G1 v+ O( C, v
            distances[u][v] = weight$ S: x, M+ o  ]( ^: j
* C. p) d' g. w: W( Z( k) U
    # 更新路径% G6 b4 N6 _: B1 s
    for k in nodes:) u3 W2 [. u( F" \
        for i in nodes:
, \1 w; ]$ Q. O6 ?! s9 e            for j in nodes:+ a5 ]+ A0 @: J" e* D# Q0 I
                if distances[i][j] > distances[i][k] + distances[k][j]:
- j# c0 ~4 b9 l/ i# \                    distances[i][j] = distances[i][k] + distances[k][j]% D1 [; d0 n& B1 t* c. u

5 r5 |7 s8 Y, k* i3 E! D2 Q7 ~    return distances4 ?+ C* g/ D8 I! F2 E# R( Q
5 w5 d% n! d6 e6 b. ~* |
# 示例图(可以含负权边)
1 u2 c; z$ ^$ `( z" ]8 |5 R* K/ Egraph_for_floyd = {
5 j, C& R2 c! y& }1 |* C7 Z    'A': {'B': 3, 'C': 8, 'D': -4},
. z" M; W  o! {) n5 ]1 I, i    'B': {'C': 1, 'D': 7},
' e" p) B  `" ]* E' [    'C': {'B': 4},
' c! d, |$ }9 W2 t& L8 p    'D': {'A': 2, 'C': -5}- r5 R3 R, `2 ], a
}
5 H( f/ h& `5 l! `0 |9 O+ X7 N( P. g) \; K3 Z9 j! S
shortest_paths_matrix = floyd_warshall(graph_for_floyd)( v$ a. U- _  R: j
for row in shortest_paths_matrix.items():7 X* @3 l" k; n5 v
    print(row)
8 B) L  `6 p7 i/ b6 w```
6 R& \; S7 f2 H: k& j
/ d5 _& p5 b2 t6 ~: b8 e## 总结
0 G  }* s" ]4 o( f; Y: S! r+ B
4 y, Y" w9 Q9 F- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。" k/ F6 V7 ]0 Q" |& H
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
8 u6 c! T) F4 `" q& J, B' f- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。4 \2 b: r& {6 g8 m% L* l
, g( F- B1 v: M5 t, B6 Y/ k
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!6 h# l" `& _& c+ _" f
! F: w! J/ p, ?; f" n" ?
$ `+ q. \$ ]0 N# J# c. K
$ I4 }0 [1 n5 M. Q! B# x2 ^

最短路径算法Python代码.docx

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

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

zan
转播转播0 分享淘帖0 分享分享0 收藏收藏0 支持支持0 反对反对0 微信微信
您需要登录后才可以回帖 登录 | 注册地址

qq
收缩
  • 电话咨询

  • 04714969085
fastpost

关于我们| 联系我们| 诚征英才| 对外合作| 产品服务| QQ

手机版|Archiver| |繁體中文 手机客户端  

蒙公网安备 15010502000194号

Powered by Discuz! X2.5   © 2001-2013 数学建模网-数学中国 ( 蒙ICP备14002410号-3 蒙BBS备-0002号 )     论坛法律顾问:王兆丰

GMT+8, 2025-6-25 10:48 , Processed in 0.927838 second(s), 54 queries .

回顶部