QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1186

主题

4

听众

2923

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
  a; |: ?, l# T& ~
1 _+ B1 F4 x3 i& s. ]$ ~5 G## 1. Dijkstra 算法5 d- H, W% F# K( |

1 y* Z1 W" i: q6 ]- L# I! u0 CDijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。
# P# m0 |0 b# Z& L! c+ l
, X" ?9 k& W4 S5 g### 原理步骤0 P. o3 D' Z& k0 J

3 s. v, J- s8 a+ X6 m3 e' ^1. **初始化**:, Y" ]/ o1 h' l9 A
   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。" g0 ]8 c, i; M
   - 初始化一个空的优先队列,用于存储待处理的节点。, |+ J1 w  o6 e, O3 `: K
" y0 t8 O$ [) b8 g
2. **处理节点**:9 V4 S$ b, x$ \" n! k% ^, x8 i
   - 从优先队列中选取距离最小的节点作为当前节点。
2 `% I7 Y; J! d0 ~; q9 h, W0 p   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
3 \  I* S( D  V) v4 F
2 f4 U# T, p, H' O3. **重复处理**:. E0 r6 u/ V6 N
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。
8 D& a8 n6 h8 W( T: s9 ^$ x
% t) M) P2 r8 @. i, \4 e4 o/ J* C! [### 示例代码
0 ~  d6 z' i# q5 E
0 ~+ r' k6 \7 |: S- ~$ G& o$ h6 t* r' u```python9 Y) d" z) u5 a
import heapq  ?3 b* R9 P: M% o+ _1 f+ Z. \: l& E

* |& v' b( G; E6 m. ]def dijkstra(graph, start):
/ \  \" H0 Y6 p: i    # 图的表示为字典,键为节点,值为邻接节点及其边权
- `, m$ i6 [7 M" O1 p- Y; ?+ q    queue = []! V( _9 p" {, l5 {
    distances = {node: float('inf') for node in graph}! L! B, I8 {; a  i
    distances[start] = 0) q1 p# a4 {/ q5 U
    heapq.heappush(queue, (0, start))  # (距离, 节点), H$ h! I8 ]% v

0 l) e2 o3 t; Q; k    while queue:
) }- i! V/ V+ C8 g  Q' ]  a  a        current_distance, current_node = heapq.heappop(queue)
7 v7 B2 Y! u" J/ N6 e; p
9 b' W4 t3 p: D$ O3 U- L" T        # 只处理当前节点的最短距离# j6 o) H8 S- C! u4 |
        if current_distance > distances[current_node]:
  D# o1 ]% ^, p3 O7 U            continue
, l( d  r& \  W2 p: q0 i4 r4 |" m7 E7 S* T2 ]% [' b
        for neighbor, weight in graph[current_node].items():
  p) n, _% y7 p- j            distance = current_distance + weight1 \1 B  h8 P4 F! o

/ G2 ?6 o( ]& l; D5 j; |) O$ F            # 更新邻接节点的距离
  X0 G6 ?2 l. G- K& r            if distance < distances[neighbor]:8 F0 w1 e  E! d% A2 m9 G. s" O
                distances[neighbor] = distance
& Y* V, S* \9 \5 L1 C5 h                heapq.heappush(queue, (distance, neighbor))
( r' y4 E# r( ?- S! v. \* N3 P' N/ _) k+ h
    return distances
3 n; T% [' u( F- k% Z* u% V) a# O" z6 j& V2 j
# 示例图! D6 b: f% a2 U" R" A
graph = {
9 o8 U& x* ]4 D2 L9 [    'A': {'B': 1, 'C': 4},
$ V. L- O, Q$ r6 P0 b) `    'B': {'A': 1, 'C': 2, 'D': 5},& F( E5 o+ P% P1 Q9 }
    'C': {'A': 4, 'B': 2, 'D': 1},
% ]2 [( y7 T2 W2 v1 J    'D': {'B': 5, 'C': 1},
; A; O7 [% N$ F3 z$ V0 Q3 g, m- H' c) n}
' }* d$ e; R$ S" H9 t
! u7 o! `9 S1 d9 i6 q; i4 fstart_node = 'A'
8 K) n6 ?6 C5 ?- k( {- {shortest_paths = dijkstra(graph, start_node). ~9 h3 s' c* ]0 L8 v. G
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}7 N( z5 e, n2 |6 _6 ?9 v- k% [
```# ]1 u5 X4 u3 ]# V0 p7 ~% R
# ?; B5 N& B/ j2 A
## 2. Bellman-Ford 算法
- T6 o9 _0 y7 U8 z& x/ p5 r' a7 z# F% `' R% @
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。& [$ I6 [# U4 f+ a' T8 Y2 a
' R* i$ M4 N( t9 m, r/ ^9 X
### 原理步骤/ R( R  w" Z* L! X; ^) j8 K

9 j( m' A2 m" m1. **初始化**:8 R+ N) {  o6 n6 q6 w# c
   - 设置源节点到自己的距离为0,其他节点为无穷大。1 S2 n) `" g) _( l% x& D

4 n3 T: T6 \6 T/ |+ `( X/ H% \/ @2. **松弛操作**:, d$ s+ S/ P; R" d- |9 j  Q
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
# a0 ?" s4 t* ~( Q
. k( G. l( q' C. L7 g( }3. **检查负权回路**:. ?5 F# k* c1 w+ L
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
0 W2 d5 W8 N/ e+ v4 |3 u7 W# K" b' a+ z  x7 v4 a
### 示例代码7 ?! S# |! X' R7 t1 Y6 U: e

' U  w( |1 T  i* c) G# [" ]```python% a$ v9 O" ?- f. b  X8 F
def bellman_ford(graph, start):
  u: F4 y6 r- t6 E    # 初始化距离8 A3 j2 d3 |  b" \
    distances = {node: float('inf') for node in graph}5 o/ e1 h8 v& n
    distances[start] = 0
9 v2 @4 x9 j( Z0 ]1 I* q6 C- ~8 k9 `
, ?" b+ h, o5 s/ F4 D, |! x    # 松弛操作( ?! C* i4 f. K& X; r9 L# G
    for _ in range(len(graph) - 1):
, b) u( o3 ]" Y: Y5 s5 J        for u in graph:: ?3 s0 w* Q/ [3 {. u. [) `# q
            for v, weight in graph[u].items():' [4 X" p. x9 W
                if distances[u] + weight < distances[v]:
5 ~0 b3 O' H$ P0 W. |( w                    distances[v] = distances[u] + weight1 x0 g: W+ c3 `( U

) L" s# C5 C3 N* w    # 检查负权回路
5 e) D0 E. ~: m    for u in graph:
4 w9 _$ T9 c* H' ]& B        for v, weight in graph[u].items():+ s+ F* K9 f* G( S& V! D/ K+ L
            if distances[u] + weight < distances[v]:& _" k1 W; _/ U+ @+ ?$ w5 ]
                raise ValueError("Graph contains a negative weight cycle")9 M: [# F1 @! s" R2 K, e
6 e3 I  E0 \- c- t3 r: |# H9 ?) D
    return distances
( i0 i- O( p& e% C$ C, ]  i* f. Y4 I  T' m. M, w
# 示例图(带有负权边)8 t# c9 I, Q. m
graph_with_negative_weight = {8 Q9 g6 h2 d+ o4 B
    'A': {'B': 1, 'C': 4},
7 p, g% W% Y6 N# u4 m6 ?    'B': {'C': -3, 'D': 2},
/ J. ~  p$ {5 n6 J2 x- g# X" [    'C': {},
7 }" j; h4 ^& r6 h8 B2 c' y    'D': {'A': -1}2 I7 s( C/ Z$ j! e$ G& A* i. |
}
6 \) {2 z- N% y; G1 ~7 Y3 O+ d4 N: r) |6 B1 p0 E8 ?- H% ]# f
start_node = 'A'
% L  Z6 J& c1 m) h# f# ?shortest_paths = bellman_ford(graph_with_negative_weight, start_node)
+ d0 P" O+ j$ z8 ~/ A# v# jprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}  `* y% |7 I  O! W
```7 j: m. ]$ V7 O

+ H9 w& F# a7 T7 ?## 3. Floyd-Warshall 算法
2 X8 |: i8 r/ n# j1 n2 W1 n
! N) S( V) `3 L% E6 SFloyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
8 W/ h  O+ g6 c* a3 h
' V& D7 k- g* K! N, k### 原理步骤
- ?% g( D8 U( `1 P8 \
0 i& P7 D7 F5 C1. **初始化**:
1 [7 k/ y* _. @4 J   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。: e- w% ~& Z$ o2 M

& }, d: X2 L: J* Y+ V" D2. **更新路径**:
) G* u! v  c9 E2 b   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。2 [( I% ^4 E$ ?+ w

  N9 `* M5 a2 H3. **输出结果**:
6 M  ^  H2 H4 T9 s5 u6 l   - 最终得到的矩阵即为每对节点之间的最短路径长度。/ `3 r5 R$ i. @' X
* e0 n0 e* G2 v4 A5 A3 v  K
### 示例代码
; {* M% s8 c4 O: g* S% n! k6 a1 f$ Y' C: R& v
```python" ^, s; L$ N0 J0 e1 v
def floyd_warshall(graph):- h3 X4 c& I+ N& E. Z+ x  I7 L
    # 初始化距离矩阵
2 l0 z1 y/ |) W' Q0 k* [) e    nodes = list(graph.keys())
* o0 T" m5 X6 [8 C$ b    distances = {node: {n: float('inf') for n in nodes} for node in nodes}- H1 S# i% w& h: ]8 f* d, ]0 @+ {
7 d) N7 G) M% l8 O! D
    for u in nodes:
4 q4 X. u/ e  J2 {6 W        distances[u][u] = 09 o: G1 y& Q. b7 L  m
        for v, weight in graph[u].items():9 y4 W4 j  G6 ^. Y) K
            distances[u][v] = weight
3 F& s+ ?* u; f" f
) X, l! Q! s$ v5 m8 i    # 更新路径3 Z2 ^2 M( T7 y3 T  ^* T
    for k in nodes:
& g/ @& ], e% s1 ?/ p! a        for i in nodes:/ G  w# A4 M' H
            for j in nodes:
/ _( b7 c; G% H. N- [1 ?                if distances[i][j] > distances[i][k] + distances[k][j]:
$ u2 ~# M- n. d4 f" P                    distances[i][j] = distances[i][k] + distances[k][j]% h, D! d% T; W0 j6 l
) V" R6 R6 z/ M+ Z  w  }
    return distances
9 B; s& ?9 g% M8 m0 w3 |
6 @; J# S2 W* e! K# 示例图(可以含负权边)
( X6 d( [: L3 @/ }# Ograph_for_floyd = {2 F4 i  v: c  w9 G+ x
    'A': {'B': 3, 'C': 8, 'D': -4},
! X# L1 n! f0 N/ o) m$ W    'B': {'C': 1, 'D': 7},
1 C/ z! a: L2 D) Z" L5 J* T    'C': {'B': 4},# n" i3 j! M2 K, M8 w6 K
    'D': {'A': 2, 'C': -5}3 d2 v' P3 t7 K& ?, s* [
}. n! @/ s2 R! x7 l% s+ `

* s$ q$ @' W/ v2 L9 u: fshortest_paths_matrix = floyd_warshall(graph_for_floyd)
9 j9 K  J4 V4 P8 v7 t2 kfor row in shortest_paths_matrix.items():: F1 m- w' k1 j2 X* Y- a* h
    print(row)
9 @8 O6 l" S0 h. Z' X3 I9 F7 K, v+ u0 M```
' k" ]* K" n. N) u
0 O: u0 z2 B' h6 j## 总结, ^+ X* e, V; k3 l% F2 ~; Z* C* B2 u
3 o! k( U5 }& C  _4 U
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
: o$ K6 x! ?) R- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
1 `1 a2 d- _% c1 S- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。5 y+ _! ?: z1 c# F9 `! S. J
4 g! m! I! e. e- v6 s9 O
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!
( i/ r0 U8 O  u. p- q; e6 ~; }+ f" J! h( h. H
: T. k/ f3 x( e/ t2 e- {$ v
8 f  k2 b6 v8 z

最短路径算法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-4-25 11:43 , Processed in 0.475911 second(s), 55 queries .

回顶部