QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1189

主题

4

听众

2934

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。0 a" f3 \/ V1 w4 G; |- p6 v  d
4 O9 Q1 M. Y+ W6 P( G9 S# `  `3 }% M
## 1. Dijkstra 算法
; b. s% B# U/ t0 w, V7 [4 k, Q
# e2 C1 e4 u  K% H; d8 _! `8 vDijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。" t; [( G( t9 }  x" {

7 U. F0 `$ [( _: w### 原理步骤
. ^( l( Y. \% {. v
7 W. X) m( Q0 ?* \' \5 K1. **初始化**:( x+ `- U  _& K# M. o% W
   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。
* T: n; c% B& D   - 初始化一个空的优先队列,用于存储待处理的节点。# b6 F. b8 H2 ?% U
; z2 F% [' o3 h1 G& f2 Q
2. **处理节点**:9 g3 w( w# H; t0 L2 X5 h) o
   - 从优先队列中选取距离最小的节点作为当前节点。6 n$ `" C; {6 m
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
( `8 j6 k- d4 t5 P/ ?
/ C1 W0 Q2 @4 s& _0 y3. **重复处理**:
6 l* I5 L; K8 [" n4 a. S( h   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。: Y0 H. r8 X' s4 y  M$ V: W/ P$ `" c

* N  |& q" @3 F) A" u: D### 示例代码. G3 P1 |# B( Z+ A4 L  u' O8 A

; `) h0 v9 v0 h. K! ^. a. l```python% R) b: u0 e2 w
import heapq
* U4 g) ^- |+ n5 \9 v0 I/ _5 j6 h/ S
* x" t& m! O6 i) x# c! l! ]2 Kdef dijkstra(graph, start):, i" E2 S+ ^6 L. f1 n  r9 b2 |6 g# [
    # 图的表示为字典,键为节点,值为邻接节点及其边权
. f" F: I' {: Q8 e    queue = []
! M( w0 s$ |! ^- T: {) V    distances = {node: float('inf') for node in graph}# I% T7 |9 x" Q/ i- ?% H3 [) D# c
    distances[start] = 0
9 z) P: f' _/ @    heapq.heappush(queue, (0, start))  # (距离, 节点). h5 _" h. o" Z1 y) g# K, l$ y- H' c

3 Q6 k: H( w& |. w; T5 Q    while queue:
6 g, j4 h$ h& v9 A9 g( }        current_distance, current_node = heapq.heappop(queue)
7 d3 |( x3 U" F2 n- d  ?7 c6 a2 N3 D7 i4 j
        # 只处理当前节点的最短距离
3 I- K7 z) m; @        if current_distance > distances[current_node]:5 e# J( Z$ M" i& p0 s: `/ @
            continue
( x6 [8 k( f% L' f1 [6 G$ \6 F# @3 Q# P
        for neighbor, weight in graph[current_node].items():, N. i, _5 P4 w- t5 H
            distance = current_distance + weight
. W9 ~7 x( a7 d2 u
4 C+ {  t9 Y1 h; z            # 更新邻接节点的距离' W* \' p4 C% r- N: S, K, y
            if distance < distances[neighbor]:/ }5 s% G5 p" x  g9 a) _# d
                distances[neighbor] = distance
" R4 K' v* \) ?8 Q) |                heapq.heappush(queue, (distance, neighbor))% O' ]! M- }0 I' x/ q3 Y3 h
5 X& x4 A( I+ d& Y5 t
    return distances( b; F0 P+ M0 S- B9 S  L) E

1 f6 R; s) S  {# 示例图
# c4 k  I* o- w. d8 }graph = {
  l# q) i  I: ~+ i8 D) A. p    'A': {'B': 1, 'C': 4},
% r) p0 @* [! s, F# d2 y9 Y" k    'B': {'A': 1, 'C': 2, 'D': 5},% J' L! L8 q0 g: K0 U6 ^: x
    'C': {'A': 4, 'B': 2, 'D': 1},
' m% M" s9 a9 D% d; C    'D': {'B': 5, 'C': 1},
2 O4 i5 M* E% y" _, @2 h! V% E- [}3 {9 ], L( A8 M' e! ?% f

% w4 k  x0 ?8 o# Y( f6 Hstart_node = 'A'
0 b5 c' A; y9 T' C7 O4 wshortest_paths = dijkstra(graph, start_node)
+ A9 i0 N- H  e& `# r: c" A, Kprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
: r) D& ?" o# O+ J```
+ U2 X& ]" A' q* {% S. A) W7 b: `7 k) i1 v
## 2. Bellman-Ford 算法
+ n1 b" M) ^* `2 }7 L# @! `+ M
. z" \( n# Z! i* I8 nBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
! @% b6 Z7 m( k7 ^2 V( y3 n; B1 `) K: A
### 原理步骤
% w/ K$ J9 j, {6 N0 H/ ~8 g: d( {; M  `( k6 Q. p( s: I6 F
1. **初始化**:& s' M9 l  f% q4 r7 P6 Y2 W
   - 设置源节点到自己的距离为0,其他节点为无穷大。7 w7 K, ^! l6 l! o# b
, Q$ X( p+ N/ d, ]. j  T% p
2. **松弛操作**:
& l2 s* G) ]$ Z% t   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。: ^! f8 }% |4 F, J: z' t

5 ]6 u+ u5 g8 G* E( Z  @/ D' t- i3. **检查负权回路**:* V; O6 ?# L, v) \3 w
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。. M, Z3 p+ O4 r8 R8 E

7 l* t; x- J- w' T' H1 p. G### 示例代码
  [& Z  |3 j- h0 c  H
7 A4 t8 O0 G! K+ f2 I```python
) B4 P  F0 N' _def bellman_ford(graph, start):5 Y6 h) Q( Y: }  c3 P
    # 初始化距离1 {2 d5 }4 b. q7 z5 P( V2 T' |: @
    distances = {node: float('inf') for node in graph}. ~' s* T9 f' D3 p( V8 @  s9 o
    distances[start] = 0
8 W* w: V# k" I* m- f% w$ `6 |/ N- N8 k( C6 W9 T
    # 松弛操作" d5 V  k; o+ ~2 N0 W
    for _ in range(len(graph) - 1):1 x; F) ?& {0 N/ j! x& z
        for u in graph:
( l! T/ O$ m" Z- W( `9 e            for v, weight in graph[u].items():
' b8 E! }: c  e) b0 j                if distances[u] + weight < distances[v]:/ q7 X$ ?, @: W$ Y+ |
                    distances[v] = distances[u] + weight8 f: D- |, M7 e" p7 e5 U7 Q, G
! j: g! O$ U/ ^& y
    # 检查负权回路1 i  ^7 T: w+ Q* x! ?
    for u in graph:
; V; R5 z% l& y7 ~( W        for v, weight in graph[u].items():
* b3 l' n1 l7 v$ ?1 ~8 F            if distances[u] + weight < distances[v]:
. U8 W+ n3 l& M+ ^5 x  I                raise ValueError("Graph contains a negative weight cycle")0 Z' Q: H; L' c% N

% _/ `5 a6 A* A! E/ _3 Y+ q0 u    return distances
& E) ~; ^7 M# \, w$ O  P- ]5 @/ L9 c+ Y  J& S
# 示例图(带有负权边): _) @& {. m# r, ~8 u: `' B
graph_with_negative_weight = {, D4 N& V5 B2 b6 S, M. Z& r
    'A': {'B': 1, 'C': 4}," z1 N* L, x9 S) e1 T9 a
    'B': {'C': -3, 'D': 2},+ _" @: l+ J# Z$ D/ f. K
    'C': {},
9 d% [' A# k% ?* w; u    'D': {'A': -1}
0 A2 |/ k, t# A5 G}
2 m% M( w7 J! w( a& Q1 n) W1 i2 S7 {$ R2 L
start_node = 'A'. I4 j/ I. Y0 P8 }$ @
shortest_paths = bellman_ford(graph_with_negative_weight, start_node)3 |/ P2 K' A! U* @9 E
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
. N7 n" v  d" Y: z```
/ I: w2 j" }3 Y0 O; S1 A& g: `; v0 Y- y% e% \1 {, L& a5 w- ^; V4 `
## 3. Floyd-Warshall 算法( L, N% X9 @- ?' |* _( j7 M  |- P
$ V2 k3 d0 j) [2 |, u8 `+ q0 W0 K
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
# g6 W+ @/ E' @& ]3 a- \4 _
( m1 V* @0 {! @### 原理步骤( G' p$ \$ \3 g8 S9 Z9 m

- I# x1 ?/ o4 J: j& ~1. **初始化**:
3 s& l( L  F# j7 x# _' Y3 ~   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。7 T4 v# T0 X0 C0 k% ]3 W
/ G; O# J+ q, S# ]+ {
2. **更新路径**:/ q" ]7 a; j! ]. t7 S( N# n! X
   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
6 p: H0 ?" V& [8 P. g# v* h3 O9 m& K% A/ ~4 e3 W* k! j
3. **输出结果**:
5 p$ D+ J. v( f( b( ~6 o) w' c   - 最终得到的矩阵即为每对节点之间的最短路径长度。
3 v, F0 B3 Q, I3 a4 T8 \/ l5 s0 E8 b: x& |; E
### 示例代码
% @0 y% X8 b/ i( z7 q" t* n; U( g: N% C
```python0 j! Q+ J2 W9 U  x' c6 r7 a, r6 x
def floyd_warshall(graph):
0 i) y/ o" Q. l' d/ N2 ^    # 初始化距离矩阵
/ L# Q1 V6 E2 J* Z    nodes = list(graph.keys())
; C! J$ ^; b+ n- H. O    distances = {node: {n: float('inf') for n in nodes} for node in nodes}) x1 g/ K9 I5 x4 L  j

6 \2 D8 ~# ?7 M2 g, B    for u in nodes:# @; t! i7 e- _' a7 w* V, A
        distances[u][u] = 0
4 I3 @  \$ K: c9 N8 P5 n8 D& k' K        for v, weight in graph[u].items():
/ _( R" S; m8 X6 g. }8 H            distances[u][v] = weight
" Q$ A/ w( W" o' O- f6 p) V3 i0 i% c. d
    # 更新路径
# @3 Z$ S( I: P7 N* Q6 v1 s    for k in nodes:
5 K' d" w' p1 k        for i in nodes:/ D& h- @* K6 Z1 w+ c( V
            for j in nodes:2 s7 y  }; t2 B
                if distances[i][j] > distances[i][k] + distances[k][j]:
# k! C, _) V& ]                    distances[i][j] = distances[i][k] + distances[k][j]2 G" ~% j* i5 k6 r3 ^( j! R8 N2 s
, u: a' f) T: s5 M% q4 _
    return distances
, R8 r9 @/ E; Q/ q2 ?" `) i4 u& Z, d5 M7 ]
# 示例图(可以含负权边)$ V- V) C: h% z6 V
graph_for_floyd = {( U7 g5 D6 q" T  a
    'A': {'B': 3, 'C': 8, 'D': -4},
3 Z% f% f/ v: b( l5 _+ ^: w    'B': {'C': 1, 'D': 7},
: m  ^2 L% N. @  u    'C': {'B': 4},, `) |2 q1 u, E  |1 E1 k3 F
    'D': {'A': 2, 'C': -5}
4 A6 e8 Q) y5 J. I}
# L/ r# R( `7 Y! W0 w( Y& ^6 V# r$ `
shortest_paths_matrix = floyd_warshall(graph_for_floyd)
) t$ U' B8 M+ e& k: n3 U/ m, U. }( ffor row in shortest_paths_matrix.items():
! @) L7 Z8 c4 o$ c0 W    print(row)
/ B* |2 Y! Y' ~3 s```  w7 c1 f6 k% R! X
* J# T# K8 R7 D- V
## 总结4 X7 l! e$ p) j& x( \% a6 g4 Q
5 G* s; v! n( A& {* b
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
& l8 Q' I& t& O3 b- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
* \& c, l. o3 q; t4 I* }1 P& Z- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。
$ T# T" ?9 [/ Z
; o* k; r( V& n) y6 g7 U不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!
9 y! Y. @* }" j8 g7 Q5 \# q/ _" @& W

5 m9 O! P3 g! c
* M6 Q; X4 r9 {( ^) k

最短路径算法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, 2026-7-10 02:50 , Processed in 0.428412 second(s), 54 queries .

回顶部