QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1192

主题

4

听众

2946

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
0 ^6 x! M0 s6 @/ j  y$ T9 k0 f- }
# e+ L# y* z" X' h% d## 1. Dijkstra 算法
8 H% b5 H- w/ k0 b# z- Y% J& N* z" q& }8 ], J1 x8 |) H. `$ Z
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。
. r- Y- Q  M( G/ G" \3 S( |/ i4 R, {1 ]7 o
### 原理步骤0 ?) W1 Z+ j3 i+ o2 X5 D
, @$ s, Y6 V. X3 h. I, b
1. **初始化**:
& o9 L# E1 g3 Q& T1 x, S   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。2 h+ v8 C' f3 p; b  ?/ p6 O$ l
   - 初始化一个空的优先队列,用于存储待处理的节点。) K9 @1 l, e: b  c/ R  U0 s
! _  z4 e' C# c# R! O
2. **处理节点**:
  c4 y' z0 k# v, C   - 从优先队列中选取距离最小的节点作为当前节点。" j4 w$ S0 t5 ]7 d- p4 x: z7 x
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
" V- M1 _, X  K+ L; p. J9 B- {- m
) Y- J9 z; `9 p! I# Q) U, `3. **重复处理**:
0 P0 H1 L: k  i   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。
( T* ^& M0 `+ o! O5 E. [0 C
2 V4 H$ @' F# j# ?8 u0 F5 ]$ w0 c! Q### 示例代码
) M. c6 a/ M/ ~+ S# D
1 W; B% @/ f' h/ E( K```python  ?6 H' Z* B- {  X
import heapq0 C/ f1 X; o1 Q( A- u/ U

5 T  r1 ^9 U( G- N7 jdef dijkstra(graph, start):
  F- j  l$ v# o' J3 |9 h    # 图的表示为字典,键为节点,值为邻接节点及其边权3 N; L* @# Q7 c0 H. f
    queue = []
, o3 P' [& f. }    distances = {node: float('inf') for node in graph}* e  B. u- r7 `  i3 g* ^$ v
    distances[start] = 0
' K( d5 C/ ~% a3 F* @  k9 u# _    heapq.heappush(queue, (0, start))  # (距离, 节点)' u) T, u4 m/ c. I) S
* q4 i; V9 c, V' o8 K
    while queue:
$ {$ e) m4 \9 l% T6 h6 F8 s, j! I        current_distance, current_node = heapq.heappop(queue)
7 I% u0 S# q( E; x% Z! l. M) q* n% i
# [' E3 n  \& ]- u        # 只处理当前节点的最短距离
. V) I7 P/ r& m% W" p9 o: i5 D        if current_distance > distances[current_node]:3 g# }( s& i# P( q
            continue
! ~4 x: C2 s- m% B* H
6 S/ I# _4 S" B4 s' Q        for neighbor, weight in graph[current_node].items():( a( z. E, |, ?1 ^# e, D( ^# c- D: u
            distance = current_distance + weight2 r+ U9 k% ]3 D9 v6 z/ H
. b* c. Y* e2 F: o+ W9 m8 I+ G/ [+ _3 T! f# B
            # 更新邻接节点的距离5 j& Z; _3 a) z9 N# C6 A
            if distance < distances[neighbor]:) M2 M- v* B7 F! p% {0 @
                distances[neighbor] = distance  i0 z: k" p1 D
                heapq.heappush(queue, (distance, neighbor))  \0 o7 d5 d' R& w1 n! P2 V

; e/ f$ D5 e, v) |1 F9 h! h5 Y% @    return distances3 n3 K7 {+ i7 ]) h
0 @) E' A- J. S/ {1 V  a
# 示例图
/ ]) n  C" |8 r' Cgraph = {
+ d# t! g$ N$ t+ `    'A': {'B': 1, 'C': 4},
8 K* q8 M2 U5 {% g    'B': {'A': 1, 'C': 2, 'D': 5},: ^) ]- O% K! [! b6 b* b4 k
    'C': {'A': 4, 'B': 2, 'D': 1},; U/ ?7 T* K$ ^' K
    'D': {'B': 5, 'C': 1},; n: g! {3 i2 U' K2 B6 T
}! |! i1 i9 i- q1 g
  ?8 x% d. z7 M1 v
start_node = 'A'0 ^1 h, J5 C. z% {# L6 x
shortest_paths = dijkstra(graph, start_node)( e/ }0 t& q6 U2 Q4 z7 D- G) r' ^
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}" d( d0 O* r4 S) y0 M  Q% t8 S
```
9 t! R. S3 E) a0 U' _
1 Y8 ~& y$ `7 O0 j# H## 2. Bellman-Ford 算法" o: _" U5 R) n6 _8 Y' O6 v  X
! @, j: l3 G2 F
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
5 q1 Q9 M# T5 Q3 S0 ^. X6 u" k  f! g5 t# Z
### 原理步骤4 f5 p( }" B5 z
2 c. w4 R. e8 J1 n  I
1. **初始化**:1 U) p" k6 {( B" F; i/ T
   - 设置源节点到自己的距离为0,其他节点为无穷大。) m7 e; U4 }4 F4 L/ z
# R+ @* Y* K5 Q0 F) M2 }  w
2. **松弛操作**:
3 A) q- W  z1 b5 X   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
9 {; G/ h3 D4 K: ~3 d( [) R; K+ ^  b
3. **检查负权回路**:
# F- e5 X9 y6 l, W   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
- k0 ~: z& [/ O$ n4 \- _
' k, E* A5 C8 e9 y; C### 示例代码
3 W/ q/ B; g) u% r7 s' W$ E  S
2 L! ^/ T( M3 Y8 L* U& P4 N' f```python8 i6 J% S/ G0 u9 Q3 t
def bellman_ford(graph, start):
# ^9 ?7 ?" w$ g7 i8 C. e# F" Y    # 初始化距离7 u# C% D$ y, \" B8 o/ R3 j
    distances = {node: float('inf') for node in graph}
; ~/ X' G, ]8 O/ \' y3 H    distances[start] = 0# a6 y& |) W, g3 L* S

1 d+ q6 @. z; S6 U' }% ~, ?8 `" `3 }5 p3 v6 S    # 松弛操作
1 B% q9 z0 q) k( Y/ K. c! ]    for _ in range(len(graph) - 1):4 `1 q! @4 P' X" n  B
        for u in graph:
* n& d! |6 W: K' `% R            for v, weight in graph[u].items():( T* I* r1 T9 U6 Z
                if distances[u] + weight < distances[v]:1 K2 _3 K% o7 F4 K% _1 a- ~
                    distances[v] = distances[u] + weight: x  E$ c  W; H  k5 N: s

8 r$ {# O- f3 ?$ O    # 检查负权回路# F5 M# r0 a) ^. X% A1 V" Y
    for u in graph:# A  ~$ {2 K( P2 a
        for v, weight in graph[u].items():; n) J: c) @8 H2 I. K4 C/ |
            if distances[u] + weight < distances[v]:; x) F; l8 F. X: ?' e3 O
                raise ValueError("Graph contains a negative weight cycle")
: O( p) m4 ^/ I
8 `. M; p' t" e. Z/ `6 D+ D- F9 b+ N    return distances
5 C( `. ?% H, v) M3 X( j, s
9 E( B$ r* t+ t; B) H, ?3 \! i# 示例图(带有负权边)* ?! G  c/ _4 s( |# _& K# [
graph_with_negative_weight = {  L' Q7 O9 X+ C. Y  r
    'A': {'B': 1, 'C': 4},8 O: u9 S) g& s2 I+ X/ j+ u* K
    'B': {'C': -3, 'D': 2},  m& j, W5 k# u6 B% k( C
    'C': {},
  r9 s0 I' {- a' y* a/ n  K    'D': {'A': -1}
' f( \2 ], K; D, K/ a}
, K- H4 F1 X7 H' g
, d1 N1 K7 a5 Gstart_node = 'A'/ ?% `9 f. S9 L, [  w
shortest_paths = bellman_ford(graph_with_negative_weight, start_node): K5 M3 H! ^- V
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
% y# |8 p4 L4 @- O6 a5 u5 _" c```
* P) A" t7 ^3 b% ]5 w
$ S4 r' y+ r8 V  m## 3. Floyd-Warshall 算法, _- O. N) z# W; n3 \

' V4 n% N0 [' p2 e) GFloyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
+ T3 {' \# D* f+ {6 V! T; ~3 w3 j) X& {2 H( G  \6 H0 a8 c( N
### 原理步骤
# ]! _' O# w( U% U) l; R8 b
! b1 _9 F* x  s# a% L9 N1. **初始化**:
. N' f+ C5 c" {4 T9 |+ L  w2 C   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。, X" s+ O& j, R6 R

% }9 u; e8 x; B. H/ d4 a2. **更新路径**:
8 ?* d; ]* `, @   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
2 J# Q# E* S, Z: q' f) [* k- U
9 L, F% I$ D2 G. }3. **输出结果**:
7 q" |& o- O( }4 e) l   - 最终得到的矩阵即为每对节点之间的最短路径长度。
& b/ J/ m2 z" u- b$ |9 D9 Q. N  P
### 示例代码) @; C; ^# O. b9 T: h' U

! o- U3 R6 ~/ K$ o```python. A! {4 B$ S; v, }7 R4 D: [
def floyd_warshall(graph):9 ?& a1 b- [  y1 u) q% ]
    # 初始化距离矩阵
- b% y. g1 @0 e8 l6 V  \    nodes = list(graph.keys())7 C/ `) r0 \3 N9 ]! ?, P' F
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}
1 L7 ~  S. x4 |. ]+ U" q/ K" s% s, @% g7 t
    for u in nodes:
, U7 J: s/ A2 s% i        distances[u][u] = 04 d( I  M2 U6 N( J
        for v, weight in graph[u].items():
& A& f! f+ z  L. ^7 N8 r            distances[u][v] = weight
. t; b  F% M; t/ ]. }9 y9 \" h) J& R+ l2 e8 h4 p
    # 更新路径$ r  a# X' o) c) D$ O5 @! ^
    for k in nodes:2 G( A  G" |/ |1 H0 `  X9 C
        for i in nodes:
% D. h- R' y/ W# ~4 h            for j in nodes:
7 U4 z2 l% |+ [, f                if distances[i][j] > distances[i][k] + distances[k][j]:
. H7 y9 f; k3 c" ^" N- Z; F                    distances[i][j] = distances[i][k] + distances[k][j], [) ^- V/ L+ E$ b' v& d/ d- A
; n; t' A& i& u  c  l( s; M& W; X
    return distances1 f1 i  N* H2 K7 {: A: q1 h8 r

% `; c( e3 o6 \! l5 ~# 示例图(可以含负权边)
) O! i% H2 o; Z: U9 W, Zgraph_for_floyd = {. g( \/ M1 l: e. b6 p8 v; s
    'A': {'B': 3, 'C': 8, 'D': -4},: _; e: h' ~, E7 [$ A+ p7 o1 c
    'B': {'C': 1, 'D': 7},
- Z; N- t/ U, N1 V% E    'C': {'B': 4},
. H! `. I3 q' |6 {9 s; ]- T    'D': {'A': 2, 'C': -5}( |+ B$ ]' u/ a2 c5 Q1 ?
}/ ^& _: e7 d* S1 c2 s7 }9 @5 J6 c5 m

" n/ {4 _) \5 H1 c) }6 Z1 w# s, N9 hshortest_paths_matrix = floyd_warshall(graph_for_floyd)
, n+ V% I2 @8 Efor row in shortest_paths_matrix.items():
1 P" F; H5 l' F: b0 _, E- C* e/ c    print(row)1 ~9 `5 x4 ]9 K4 I3 N
```
, P' t4 R9 L* i4 n3 e1 c
4 ~" H3 A7 U5 \; G## 总结
1 ]' S% A) w* L0 e5 @  {# u) V$ ]
: z8 O; @4 E  r# p6 }2 I- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
6 F6 u; f) z2 t( a- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
0 O* `5 R! B- _$ i9 F- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。: N7 C/ C: |8 Q" ~2 p  Y" g6 e7 s
! m  J' i1 n% ~
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!
+ E% l% H, N+ J# ^& r
8 S9 t/ y1 W* h5 Y3 g7 p- u. h- W# X/ Z

+ n* V; l! n: D) n3 n% v" M

最短路径算法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-8-25 06:20 , Processed in 0.652067 second(s), 54 queries .

回顶部