QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1198

主题

4

听众

2975

积分

该用户从未签到

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

! z# j& g  {6 E4 p% m## 1. Dijkstra 算法
% W4 f# Z+ G2 `5 z8 |$ m! u4 z- w  Z& U- j: e; m
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。! {3 C3 l! X; {# Q! S: \' q- w
4 R: }& b! o0 S! P: a
### 原理步骤
& a6 `+ N! n) `; G/ W! Y. x5 u( C: ~" g7 G; R: d  _
1. **初始化**:
+ r/ M! g1 z; t9 D7 x   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。6 s9 Z% c1 T# p6 X5 w5 B  c* x
   - 初始化一个空的优先队列,用于存储待处理的节点。% z, O! x  y! b9 R
# ]8 H6 K% ^) V0 Z! U6 X/ ]: N
2. **处理节点**:
9 B8 K6 [8 T+ L1 N/ p: |/ D+ z" p   - 从优先队列中选取距离最小的节点作为当前节点。( ^$ N/ q! T1 g/ F! x1 ~& N
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。: T9 ]" s" N8 s! f: ~
8 X5 A! B1 n; \# k7 {  L& `/ `/ g
3. **重复处理**:- G1 ~# k) ]8 P! [
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。) d& }) T1 n9 H# g
* {: R, X& r/ e! P6 y( _
### 示例代码
, m2 Q* l4 N: H0 J" q
5 |+ s- w' o" u* t8 Y```python0 E! E' r6 j. ~' J' d
import heapq
' E6 N: x5 v1 L- t  X
/ [8 I0 ^7 n, Z! f2 }$ s; Ddef dijkstra(graph, start):2 P: q$ B) \( `* c
    # 图的表示为字典,键为节点,值为邻接节点及其边权9 F  g0 ^" A& n4 p( K
    queue = []
/ `$ _( {7 ~2 [, R/ m    distances = {node: float('inf') for node in graph}
* Z. I! K0 U' N1 y3 d  v    distances[start] = 0
- c8 U5 `( b( z9 B    heapq.heappush(queue, (0, start))  # (距离, 节点)
8 {! C5 q. Y' ]4 l
/ ]$ E5 g% w1 o- K( d+ a    while queue:
! f- _- ]* R( F$ D        current_distance, current_node = heapq.heappop(queue)0 M3 S/ t- X+ v  ^
5 H; O% Q4 y% l; D) e& q
        # 只处理当前节点的最短距离% w  G% O; O4 F  |7 i
        if current_distance > distances[current_node]:  T/ x$ a, c) e) ?
            continue
" Q3 g7 D+ u7 k- \
9 D6 K3 v5 U( Y8 m3 O        for neighbor, weight in graph[current_node].items():: D! i% ^& V1 ~
            distance = current_distance + weight
) ~- ?/ @5 C2 P; o4 ^# n; B1 r
- ~! L$ u7 p- F; X4 q9 k            # 更新邻接节点的距离4 V3 o# r4 Z( ]
            if distance < distances[neighbor]:, B  C* F' W# U  Z
                distances[neighbor] = distance
: x; [+ L4 Q8 z$ M# m; }                heapq.heappush(queue, (distance, neighbor))) i+ `( h2 I6 d/ q  A

. v7 \7 Z) _; @    return distances. F! m" Z4 N8 p3 i8 o/ Q
2 M4 B8 q6 }  P. i/ o+ r) S  V$ [/ _
# 示例图9 z! a. U! [& E/ T* D
graph = {
2 X% g7 {" \& c& Y8 d3 k* F    'A': {'B': 1, 'C': 4},8 ?; R; W" H7 G- s
    'B': {'A': 1, 'C': 2, 'D': 5},
+ Y* B/ n. s$ @    'C': {'A': 4, 'B': 2, 'D': 1},& p! G# J) N+ d. w& c
    'D': {'B': 5, 'C': 1},
6 C7 e5 g# z6 j8 t( }) q2 ^}
& i1 }. @) F: W
6 S- V, E( G$ m2 G* [7 Xstart_node = 'A'
" q, ?9 z! Z: x" }& Q, u  w+ ^shortest_paths = dijkstra(graph, start_node)
$ R6 x9 c3 Q' n. h. G! sprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}* G; ]( X; [8 i
```* J, s- u: @( N/ g9 e
  h2 _- w* A5 h3 D2 u  \: e
## 2. Bellman-Ford 算法3 A& p& z' a3 h, i& y9 r

" I4 B2 d( x! _Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
( ~. q4 e6 `% h2 t, B( q
% f$ a9 p! q; {0 e' h* v### 原理步骤
3 C5 v6 H6 D) S; d" D
; E+ T/ b9 S' V- H) T1. **初始化**:% S7 x& H# k  b! C4 N; L- q8 H$ Z& X1 \
   - 设置源节点到自己的距离为0,其他节点为无穷大。
0 P5 v. R6 j3 k1 t' g
, C. R; ?7 S4 x6 Z& i2. **松弛操作**:0 G# m7 u! O9 r- |, w
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。1 X# x) g  i2 m4 A  h- G  U

0 i) s$ P3 ?/ r- ^3. **检查负权回路**:
! [7 n8 a( E# K9 E6 }   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
! R+ ?0 u; {  j6 q  ?1 O3 j4 c
. H8 ?# k  S" q### 示例代码
: v+ y" U9 e/ h2 _. V$ K3 x5 f$ P8 Y7 H0 B& I; I7 ~
```python
" V2 @% p9 t$ s2 @* Zdef bellman_ford(graph, start):
! y: T( J- g9 z5 ]* \/ z( _    # 初始化距离& J& j+ K- b6 u; ^
    distances = {node: float('inf') for node in graph}
6 g3 C: |8 e& Y# F; C: @    distances[start] = 0
5 k% I2 i) W# N8 C6 {. T- W: L9 E% ?
    # 松弛操作: u- V! C* y/ e6 t
    for _ in range(len(graph) - 1):' d- V, J0 s! H0 u6 p8 C
        for u in graph:
9 h% J* C7 t6 @/ ?" v% i            for v, weight in graph[u].items():' u2 ^! s( S+ j& ]5 J3 U0 m# T
                if distances[u] + weight < distances[v]:" N& k4 X+ x9 r" E. J! @
                    distances[v] = distances[u] + weight7 z# {  x/ o' F5 j/ U2 s
# s, ]9 T( Q' K  g) p+ ?; `% Z
    # 检查负权回路
* v/ j9 G1 h* i4 V. ^    for u in graph:
; O  i, g& R* V3 n' f' y2 ^4 n; e        for v, weight in graph[u].items():: ?/ N3 j0 ~5 E4 u  i$ v$ ^+ U
            if distances[u] + weight < distances[v]:
; k! C1 J7 j! }                raise ValueError("Graph contains a negative weight cycle")0 W6 q0 D' C- @& r: Y3 R& w
9 a# |4 T/ c9 b+ S
    return distances" E# A/ z) ~+ D8 n
: |  m/ t: ?" H7 ?& s) I  l
# 示例图(带有负权边)
8 a% {7 s) m, w3 w* \3 R: lgraph_with_negative_weight = {
3 N/ `3 M/ V$ @  n2 L    'A': {'B': 1, 'C': 4},8 [5 E/ O  Y/ f1 K" v0 b7 k8 y
    'B': {'C': -3, 'D': 2},
$ M0 `" h0 \( A3 p/ M4 S    'C': {},/ A: C  f/ q! ^# u3 P: C4 R# N0 A
    'D': {'A': -1}: R! b- z; f- h# z+ ?
}& l( q) h# x9 I1 V0 x

- f' {2 O" S$ B2 V" l1 zstart_node = 'A', s% F- i0 U7 b; v6 `7 f
shortest_paths = bellman_ford(graph_with_negative_weight, start_node). o2 u& }4 L) q2 k
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
) o( H+ n* q7 [```' ^. P; x: Z) v
, u! F) `9 [! m! Z! r5 ?
## 3. Floyd-Warshall 算法! v! S8 y, ~+ Q8 t/ r  p/ v
+ f" S' b1 q4 E. L0 h/ l, w
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
0 s; v# e$ [7 Y8 E6 \3 d* P/ z) X& r& J% e5 }
### 原理步骤8 k/ [9 |  U. J3 k
) D3 J7 w/ w. ]1 |
1. **初始化**:
; L9 [' l/ E* d" J   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。5 _0 S5 t1 D) E, s

3 W* d7 i# ?. P7 b7 `2. **更新路径**:2 J7 O3 l6 s. O( }# f# o
   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
& K7 x$ j6 n2 y+ J! A+ ]* X8 S: d8 i9 s
3. **输出结果**:: p: O3 }$ G* R" t
   - 最终得到的矩阵即为每对节点之间的最短路径长度。
4 v9 ]- r/ T1 L  U0 l! x" D6 Z: Z' }5 z& r# h
### 示例代码
; R) l7 G  x  L" E$ z+ v5 k. d
+ Q& g6 A& D3 }( K! j  k+ K3 v```python
7 u1 T4 k3 U+ K. a& U7 H. r) Hdef floyd_warshall(graph):
( M( F- S: _. s% z6 S3 R' D1 O    # 初始化距离矩阵
) w, x6 P' h7 m/ ]3 \& u8 h    nodes = list(graph.keys())3 e- N+ t% f! O( R/ G0 P
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}
# a0 x6 P: b/ z0 S. q0 w$ b- }
% q# u* D" f0 U* r/ \/ L' ^, j    for u in nodes:4 c6 T: Q* ~5 ^* u
        distances[u][u] = 0+ [: b- |9 c; }( p( `  a3 I0 o
        for v, weight in graph[u].items():) ~1 ~# p/ }8 w4 v2 R) i
            distances[u][v] = weight3 }* r% {# ?% B. ?5 [9 Y) f! D
( f4 E, n, s0 v; ^& g, s4 b# _" k' Y
    # 更新路径3 l1 e  N1 K; M4 }# J
    for k in nodes:
, M4 Y' |+ y3 c( Q        for i in nodes:
( @  u7 r6 |0 v$ E, e# T            for j in nodes:* p8 V7 T+ @+ K+ _' E/ `
                if distances[i][j] > distances[i][k] + distances[k][j]:9 v+ r. I/ I0 Z" ^0 n8 a
                    distances[i][j] = distances[i][k] + distances[k][j]4 A6 Q7 l- N. R6 _. }* ]$ i) H

$ Y1 ~. K. X: P3 X/ g$ c# B    return distances
: R, j& ]! k6 d! d) p, h
0 b! p* m' ^  r6 D+ t# 示例图(可以含负权边)
# E5 s8 h# v4 R+ i2 _/ @. Fgraph_for_floyd = {
# M/ a" Q8 F9 w0 |! R$ M) ]3 C" {    'A': {'B': 3, 'C': 8, 'D': -4},
1 f2 {- h6 M) |    'B': {'C': 1, 'D': 7},3 `' B6 U7 o* m' ^" a
    'C': {'B': 4},4 r, f3 b6 Y: {/ L
    'D': {'A': 2, 'C': -5}  U8 ]7 Q- ~2 v
}
- d0 m* |; n6 y6 w9 T6 s8 \. z' G+ |: X7 y9 m! l7 S( u. W
shortest_paths_matrix = floyd_warshall(graph_for_floyd)8 d  P8 L( _/ K1 f( F' T
for row in shortest_paths_matrix.items():( H1 x7 z2 C3 X3 a9 d. f7 _
    print(row)
% H$ V7 h; e0 c( ^# s9 u: [+ v```& L5 [6 d' L1 A$ F( u
# K& [+ _7 B& k1 K8 n; O, n7 G
## 总结5 w0 H5 {# S* S' f8 Z4 k, v
4 N) g6 z5 y. F! @( ]6 B& j- c* ?
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
" v4 K) j; j: T2 |! f0 M" F: H0 Z- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。. T0 H/ M2 K- ~/ @' @/ X$ `
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。
, s9 A! N' j6 {6 r0 }3 M& }9 y
, R! T  L) d& d' X$ e  e$ n不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!/ N1 i1 C: F1 P8 [
* ~& M- s" n9 _, E5 h2 O+ t
8 j% f7 I  b9 X& A# t$ `* [( m
! U7 x! e  I& a! l6 y- f$ U

最短路径算法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-9-12 00:23 , Processed in 1.027763 second(s), 55 queries .

回顶部