QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1189

主题

4

听众

2934

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。- ]& U* c+ K$ J7 b2 y: U3 V# p

7 _0 V; B& j* t$ u" |& [+ h## 1. Dijkstra 算法
! n, t" o  l! _" Y
; C7 @& a6 `$ ~! U- `Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。+ X2 n+ I3 O# G! x: _8 F
/ S$ ~4 @+ M% w$ l$ w" m
### 原理步骤; r  p& t4 H# k1 i# j% C

. j) O1 M# h' v& X4 d9 f; L6 l' J1. **初始化**:
  `) q: e. a7 i) G  `) Y   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。) ]1 m3 z8 c1 _- ?
   - 初始化一个空的优先队列,用于存储待处理的节点。4 _' c9 ?% j. Y  g( u% b% \
6 ^  ~4 ]: n; ^1 Z  c& n0 W7 t
2. **处理节点**:1 v1 T  H  z# w. U  `
   - 从优先队列中选取距离最小的节点作为当前节点。! x/ w6 f8 h) k* L3 u( D7 F/ w' w
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。' b, t" J* I8 C

* I) p" V, o* U- P8 U3. **重复处理**:  y; [) X9 x6 ]7 f2 |
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。1 R) e& B* P$ z

4 L) z" @; t7 c$ _0 A1 b### 示例代码3 _. h% A/ _9 l5 E9 q4 w) U
. }" K' o2 }* F* A( J1 D
```python
& ~; g$ n' L/ g$ F+ Dimport heapq6 O+ k! p2 k: T3 l2 c
: q! k9 X( [6 [
def dijkstra(graph, start):
, d4 y: y; Y" i0 @  M/ x) y    # 图的表示为字典,键为节点,值为邻接节点及其边权. l  h4 g' f3 U' ^/ y) p; Z, a0 b
    queue = []
  h9 ^$ j0 B. t1 v: t    distances = {node: float('inf') for node in graph}
: l7 Z, J% T2 P! U8 p* Q- F. X    distances[start] = 0/ n  C! T) ]( h7 H; Z$ \
    heapq.heappush(queue, (0, start))  # (距离, 节点). M; K9 B9 ~* i7 |
0 p& |2 q6 s) n) x5 k6 `
    while queue:; R' e& f/ J. [9 E. n
        current_distance, current_node = heapq.heappop(queue)
5 t9 M0 v. w8 ~, u4 H' @; b9 |1 I
- [# }7 b+ m3 F3 N        # 只处理当前节点的最短距离
& y6 }7 L- F& o; F        if current_distance > distances[current_node]:7 ?( j7 E$ S: S& h* l6 r
            continue
/ W5 C/ G# C! L3 H0 [4 ?! {0 M8 `! F; O% n* A  `
        for neighbor, weight in graph[current_node].items():1 y0 T) {) _' W: Z0 p# Q/ G4 T
            distance = current_distance + weight
( u" J9 \) z' Y$ ?, w& W1 O9 \- E2 |' a
            # 更新邻接节点的距离. ^% Z2 J* Y9 w
            if distance < distances[neighbor]:+ [5 k- }3 s7 D8 b8 K
                distances[neighbor] = distance, ^- H9 X* [* e0 j1 B& N* H! B* E3 `
                heapq.heappush(queue, (distance, neighbor))% ]; w3 R7 O! E& ]. ]4 T

4 Q0 Q  p# t& n) G! }6 ~# }    return distances
/ P6 v( \3 A) J: U/ c- B( l
% F1 J, q1 z. Z9 a6 q$ n) w9 s# 示例图4 _* P; H$ h3 O. n( v+ H2 w
graph = {
# V$ o# f- |% r) P    'A': {'B': 1, 'C': 4},; U1 Y8 y; \2 A* I" p* V) }
    'B': {'A': 1, 'C': 2, 'D': 5},
" _  o# A2 ?9 `8 g/ n    'C': {'A': 4, 'B': 2, 'D': 1},
+ m: E- x& a8 S/ D$ z    'D': {'B': 5, 'C': 1},  j. c" g0 a. u+ i- p
}
; z0 W/ u0 k- O/ @, R7 j% Y: S
8 }4 ~  X- d( v6 {start_node = 'A'
! M# n/ d" ]3 ?4 L  u' nshortest_paths = dijkstra(graph, start_node)
1 g- `2 g  s, v' F6 H% Y% lprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
$ O' G4 w2 i9 g1 ?```
) s9 q$ X2 t4 T& z
: H% C& x( g" w7 T## 2. Bellman-Ford 算法8 C! n3 p( Y" a; t" k# J0 k
, {0 _# F. k( D4 D) H" P" v1 Z% s
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。3 h2 n, e2 @# l6 p3 y

* ~( `! o# j* [1 t% J5 s% Q### 原理步骤
* W  `6 u/ r( p% H4 F7 Z: _" L: U0 P5 H9 [6 j% G
1. **初始化**:
2 H* N. W- V+ ]% D; S' x   - 设置源节点到自己的距离为0,其他节点为无穷大。
6 [) r1 K% {: Q1 z" O6 V7 u+ M8 X9 N+ ^8 G1 W2 n- x- p2 ^& v" k) g
2. **松弛操作**:
1 Y5 O8 L  a7 ]# o- ^   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
& I* j% x, U; A- O2 Z% s
; J5 S* X' d5 \3. **检查负权回路**:3 C7 q; J1 r5 u' V: ?
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。4 |7 A+ n! ^7 w) R/ A1 H3 m

! p/ x3 f% d3 |9 d* X* z### 示例代码. x7 B/ }% z, W& K0 W

. M5 i/ l1 D# P4 S. o```python
3 t7 D5 {1 P, J( m) odef bellman_ford(graph, start):5 u0 Q  Z1 F! h: @* C+ ~
    # 初始化距离: r0 f/ `6 n$ D! L& Q+ m) L
    distances = {node: float('inf') for node in graph}, J1 v* K1 J; }4 i$ X& N( j
    distances[start] = 0
/ I* X/ F$ N: h
! B  K! X# O& V8 m4 S    # 松弛操作" H+ v+ i5 d9 D' T, ]
    for _ in range(len(graph) - 1):
. P+ a! U9 T8 C1 X        for u in graph:
* L+ P: q, L0 P3 d            for v, weight in graph[u].items():
5 j# ^6 x( }% Y                if distances[u] + weight < distances[v]:  W" M! h: N( F6 H$ J, T
                    distances[v] = distances[u] + weight
& h' K# o4 |8 I1 y+ E9 l7 A8 t: i  a+ `4 ?) l: D( u: X
    # 检查负权回路
: i, f+ ]$ e  h; j3 E3 {    for u in graph:$ o/ D, l7 G2 l. i" j
        for v, weight in graph[u].items():6 R, c) o0 N$ C  P4 O
            if distances[u] + weight < distances[v]:
8 c" T6 f3 O7 A' G1 |, d                raise ValueError("Graph contains a negative weight cycle"), w, M1 Q% d4 h: J4 d) i
1 d  Y. t8 l4 Z7 ~; d9 w% g
    return distances' P% G% \, q" |* ]* e/ w
7 Z: V4 _) Z( U" I1 |
# 示例图(带有负权边)
2 ]$ p# s1 d, y& d8 G# |2 Hgraph_with_negative_weight = {
0 b: `. Y8 g2 I$ s' |! `    'A': {'B': 1, 'C': 4},
3 t' r3 P$ K2 |    'B': {'C': -3, 'D': 2},( a. V* W/ a+ E: h+ x: I& K
    'C': {},
! t  t, T, e* h1 c    'D': {'A': -1}
+ l. ]1 ]* `! T, l- v}
- `! Z' V4 O4 }
4 u+ i0 S8 \/ A3 ~# z- Mstart_node = 'A'0 T9 P1 v# o6 z
shortest_paths = bellman_ford(graph_with_negative_weight, start_node)0 Q" a! a. r1 s3 Q# c- R
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
7 J+ Z3 b/ w& N3 T2 {/ o```# C( V6 ?2 M4 n1 M2 e+ J# x
, \' f$ j. T) a/ i# `+ a9 \
## 3. Floyd-Warshall 算法" l$ s4 g/ Y8 R( a$ T" _2 b/ Z
/ X7 }3 T1 s) e  w* y
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
+ |: p3 S1 O  S9 C2 S+ N* W% t: o* W
: Q5 e% l8 `' w* ?3 p& F### 原理步骤9 T4 s7 L8 n, |0 v6 Y" t, Z
4 F3 B5 b( G& B( o5 D9 s" ]
1. **初始化**:
  H  ]' Q9 Z, F! u4 A   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。& Y5 W0 u2 }/ a8 P) f
& y% \; B2 e# J9 }) I5 R
2. **更新路径**:
; s9 `7 e$ n. U9 p" R   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
( L: S$ e( B5 I# C) Q* b1 S3 N5 U9 l: G
3. **输出结果**:
. F3 f9 {% p! V  x) Z* L   - 最终得到的矩阵即为每对节点之间的最短路径长度。, j7 h2 n  ?, a, W' f+ L; c$ ]/ r
* \8 U, x% W, s1 @) \" ?
### 示例代码
( S" q/ r( f6 R- }' ~9 ?7 ]" F) D0 B1 |! }" U
```python
/ T+ W% [3 Q2 H  t- {) f4 cdef floyd_warshall(graph):( `- A3 C# {) g* A4 L3 o6 @+ W
    # 初始化距离矩阵
3 [/ {: @7 f; F! n. B    nodes = list(graph.keys())0 G4 }, z; y! f8 D! a
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}% y+ g/ _0 j( z

, c2 `2 N3 U  P1 m. [- K" F, H    for u in nodes:
6 l3 c! A" q8 i/ M        distances[u][u] = 0" I" K1 ~" L9 W. l& W% F) j
        for v, weight in graph[u].items():
, S& x8 o- x# i# W8 L4 l3 I            distances[u][v] = weight+ p. S/ F1 d$ A) B- N
5 S2 @$ V& Y+ ]5 V
    # 更新路径
, l* u% ]8 q, O& d- C/ G% Z    for k in nodes:/ J$ D+ k! {' v$ ]7 C( v
        for i in nodes:3 R  k5 J2 q; V/ g8 n) X
            for j in nodes:
8 ]8 j3 e( R2 o3 e) _+ ?                if distances[i][j] > distances[i][k] + distances[k][j]:
( `* E$ R) P1 T+ o4 E2 i2 L                    distances[i][j] = distances[i][k] + distances[k][j]7 b* A# ]0 e5 p3 P7 i
7 U, ]( E$ w' T$ T4 h
    return distances
* V' a3 o$ {7 f. x' g- Y, H$ u! I( |% C& ]( A
# 示例图(可以含负权边)
, X) j; d9 `- l5 a) p) g4 u& T4 r! m9 e. _graph_for_floyd = {  ~' H6 ]1 l9 T/ S# t4 r
    'A': {'B': 3, 'C': 8, 'D': -4},
/ h) c3 ]) K+ t* ^9 w! y    'B': {'C': 1, 'D': 7},
3 |0 O5 ^0 h: [+ }0 p+ q. h    'C': {'B': 4},7 a* Q* L. n% g+ h! Z9 h
    'D': {'A': 2, 'C': -5}
8 U) C/ U" O, ^) V- f. }( q}
0 i; Y$ X# Z5 l6 V: E' T% L" T" V. C! |. X  s# c1 F
shortest_paths_matrix = floyd_warshall(graph_for_floyd)
% ~( Y, H$ r  k5 \for row in shortest_paths_matrix.items():6 N8 Q! u% x/ |% C& z. I- U
    print(row)
: P  s2 n/ o; n- I+ M```- d2 A7 F6 Y+ J1 m' p
1 v( j! m+ b* o- K0 P3 t" z
## 总结9 a- b5 y1 _( I- h$ C

4 z3 S5 Q  V, l- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
; D8 A/ E8 K6 k" T* c3 O  _3 B7 K- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
3 T4 s2 M5 A  r- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。. E3 L3 H- ?% X2 y* v( a* g
. [( W. T  A8 }  p9 H9 I6 B% J
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!2 \& _- j' c1 s
$ J4 H5 ]* Q; I, E% b+ L+ B

* j8 y9 y5 |0 k/ N1 \0 E8 Q# y3 }8 M( `: q) a3 B

最短路径算法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-6-12 10:09 , Processed in 0.302862 second(s), 54 queries .

回顶部