QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1198

主题

4

听众

2975

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。# r# f" B( I' B
! B  E% o" @9 Y1 H
## 1. Dijkstra 算法! ]8 Y3 C& ?3 I& d5 h# |6 Z
% u* h; T- S8 V2 r1 R
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。  Q3 Z+ a! P9 u8 S- K
6 V# x- a% E8 ^( Y# i, Z8 I/ a- k' B
### 原理步骤% r8 d! W0 w& ^/ W5 y; B8 M8 J! a

0 j  D- |  M/ Y) i' y# l) x8 ~1. **初始化**:5 }5 h4 ~) v* i. e% h
   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。! R7 `$ w0 d( e* ^& T" C) V0 U
   - 初始化一个空的优先队列,用于存储待处理的节点。
5 e8 k# @  v, i, O9 Q# u! y5 ]3 ^8 s, e
2. **处理节点**:
+ u" L5 g( B! `/ F. h+ u3 l9 ?# y1 P   - 从优先队列中选取距离最小的节点作为当前节点。
; G* w8 x" L! O0 M   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。+ \1 f. \; W/ f

/ B# A5 ^( ^( O# p( S! {8 a2 x9 z3. **重复处理**:
5 Q& j9 Q1 K5 p8 J) }: @1 D   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。
  ]) Z. r- @1 T+ d5 ^3 N4 C  B2 D' l8 v2 W; S
### 示例代码$ P' s" F; N1 c2 p. _
* u) l/ n( D, y& m
```python$ \/ F- ~  f! p5 d; ?4 q
import heapq
( N5 r' y/ G/ [' [# E4 g; _- k& D  B- r; i# M6 T
def dijkstra(graph, start):
5 ?& J3 j; n9 r2 q! e    # 图的表示为字典,键为节点,值为邻接节点及其边权
# ]4 ?- s& l. @1 {# B1 m    queue = []6 W& j- {" s+ V
    distances = {node: float('inf') for node in graph}
! h, z, i1 ?' W; {0 g" v    distances[start] = 0# Y; s) T- t4 |9 j7 s- \
    heapq.heappush(queue, (0, start))  # (距离, 节点)
! G8 I. \6 L, p+ q6 i! ?" s. G7 }3 n5 T
    while queue:1 |7 @$ V1 x6 u# y
        current_distance, current_node = heapq.heappop(queue)1 e8 D+ v$ f- L% L/ M' D$ b- P, @1 E
- j+ ?3 v0 T/ T3 L$ j* i0 l
        # 只处理当前节点的最短距离
* S5 D8 m' _6 M        if current_distance > distances[current_node]:; f. {% p2 V& }  ?5 B
            continue
. ], V6 l* R# t1 j# U4 b8 f! l" B8 v* U/ L
        for neighbor, weight in graph[current_node].items():2 |" `+ z' t. O2 M
            distance = current_distance + weight( s! Z6 r5 c9 S/ a1 p3 v5 s2 N
6 }6 T& \. J' Y+ U# f! T0 ^* W
            # 更新邻接节点的距离; g$ m; i) t9 K& O3 Z' G
            if distance < distances[neighbor]:. y, K( Z; M8 e5 @  \4 x0 j( `
                distances[neighbor] = distance# C6 C9 {9 B/ _
                heapq.heappush(queue, (distance, neighbor))% `% y) N" a& J! q! s$ K3 z3 E, u

# D5 J- ^4 j4 E" U% ^    return distances5 X) W  O4 p$ M+ f

% p/ ^$ x: F6 m! {# 示例图
! P- Y' _* _" Rgraph = {% O% c- F; X+ L$ M8 F3 `0 N- ^
    'A': {'B': 1, 'C': 4},
3 I6 T6 q6 d; Z# U    'B': {'A': 1, 'C': 2, 'D': 5},. D' H, n1 x5 J3 j
    'C': {'A': 4, 'B': 2, 'D': 1},
" q+ C# q# n) I7 Z7 z    'D': {'B': 5, 'C': 1},
+ m0 ^) D2 @% p}
  S& w! Z  u( V* D' ?; S/ h5 p+ R3 p* }" f0 ]
start_node = 'A'8 p1 W8 ?: q( ~8 w  I
shortest_paths = dijkstra(graph, start_node)' C  m; J. n, A- N' Y! i
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
8 H# v0 P# i, b& ]```. a, \+ A( D( j# P
7 k5 j4 g( |$ d6 D. L
## 2. Bellman-Ford 算法
+ H( Y* |; t+ u: k. |9 ^8 U  h: m- R( J1 e1 n8 B9 c! ^
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
5 n& ^9 X! V1 N5 s6 ?( R
6 d) m) A2 e- o### 原理步骤
: X- \& B, T( {) v: j9 N* q  y
2 F3 x3 M% m" i1. **初始化**:
/ ?0 e2 f9 h7 l& ~' k) S$ [' ]   - 设置源节点到自己的距离为0,其他节点为无穷大。6 Z4 r) m+ u: l; q& }( `
$ K1 e- ?+ Y- N1 c% r
2. **松弛操作**:! K3 J4 j9 f+ V0 F. Y
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。4 I0 n  J. Y6 E- a5 w6 {1 m
2 [' e4 t, w' L& A& [
3. **检查负权回路**:* V, J$ k9 `/ Y# x- |. I" B
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。: n6 W9 `- X9 l- R" ]
( h8 m+ g) r' i
### 示例代码
. f& \9 e+ g2 v8 f9 L1 I) |5 S; [# U
```python
/ \6 j3 {( `. e$ Ndef bellman_ford(graph, start):
# ^" D& v( w. v" ?- p    # 初始化距离
# L* ?. c9 a4 i1 g. D5 f8 c: O    distances = {node: float('inf') for node in graph}
0 z& U" {, `5 a& o; F  E* I    distances[start] = 0
( ]5 @- U' T/ B1 E! ^; D6 l( ]5 M% B) [( e
    # 松弛操作
6 b! S! r- r7 y' [6 b    for _ in range(len(graph) - 1):
7 U; P- x( ?5 Z( C/ M        for u in graph:
7 \; g- ?, W" ]9 l8 ^: q. u            for v, weight in graph[u].items():
+ g  u+ b+ k( R+ ?                if distances[u] + weight < distances[v]:, v+ ]; K9 ]) k' i: P
                    distances[v] = distances[u] + weight
+ e* W7 f+ G4 i; ^, i$ H8 j1 ^) f+ D; k9 {5 o1 J9 X: a* E2 _) G
    # 检查负权回路
" H  M! p& l! @9 h& L; W7 u    for u in graph:# }# w6 L0 B% H9 f" Z
        for v, weight in graph[u].items():
9 Z( ?. I. q' d) H6 J) k" A/ A            if distances[u] + weight < distances[v]:
2 r. \/ j% q2 y. @! j4 o; U                raise ValueError("Graph contains a negative weight cycle")2 p. P$ H( M  m1 S4 L% V' p4 |
6 i/ M$ i, Q# k  Z! r! a
    return distances
3 `! [5 X5 L7 p! w9 ]1 r7 ~5 S( Y5 f3 ^
# 示例图(带有负权边)
9 I) @& M0 I" R3 x) Rgraph_with_negative_weight = {$ w5 ~- H# j: e: Y; x
    'A': {'B': 1, 'C': 4},
' w3 q' ~, T- P* P5 P" i% @9 Y% J% X    'B': {'C': -3, 'D': 2},& Q7 N* B& {2 I
    'C': {},$ b$ Q8 P* Y4 k: o; l* V
    'D': {'A': -1}
; v, p% N6 b# _) Q$ ~9 e" k/ E5 P}
9 E' `; G% d9 H* i$ H# O, x, u4 ~& p6 @0 [
start_node = 'A'
7 D& A  f* I. s: @. g" Vshortest_paths = bellman_ford(graph_with_negative_weight, start_node)6 L" c( @9 B4 q5 a1 P( H
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
1 R. d7 |/ E0 u1 [% a```
. W! f) g+ T  J+ X
! g  R7 q) `% Z* C3 P3 ~1 J) p# T## 3. Floyd-Warshall 算法/ S3 w* Z* g3 k3 h7 b3 x
! I3 C' m  {, F$ @* v5 L3 Z1 O  S
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。5 Z& D, @# ~. K
8 R6 r* f% ?/ F1 E/ o0 S  T
### 原理步骤
& q5 O1 \, D& Q% Z3 c, R6 n
( w; U6 y- ^  |' k' R2 R1. **初始化**:
, r% E5 `* ]: |6 M   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。2 W- c4 x. n. z

( O) O( K; c' H( c2. **更新路径**:( V1 ?: _6 n$ C& Q$ y( L- {
   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。9 b9 K* P& w, X6 p8 o9 b
0 Z: Y, f' j0 N' d
3. **输出结果**:( ~9 \! v% O" y( j% V5 e
   - 最终得到的矩阵即为每对节点之间的最短路径长度。
1 c6 t1 n' t1 ^4 X9 ?
& R; v6 ~7 K3 D1 p" t$ f) f4 c### 示例代码
* J  j: E, v& N6 v$ b/ `
) Z: _" k3 R2 H5 m/ M  _1 N: z```python  ^  p# }# h. s( h# C
def floyd_warshall(graph):) m  g8 U& Z9 b
    # 初始化距离矩阵5 e/ x( ~+ ]. d. M+ o9 A. D
    nodes = list(graph.keys()); s+ b7 V# c& F) {
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}3 i0 \" }( Y+ a3 E5 q9 `7 T  N

: o8 K0 Q# d5 A    for u in nodes:
6 p( \+ M: i) D+ D# v" T+ X        distances[u][u] = 0
2 C% b. [7 U2 b. n        for v, weight in graph[u].items():
' B3 L+ w/ z, _- G            distances[u][v] = weight
# j+ N  B5 X: a5 R/ @7 C! }7 L; l  s( |1 J+ c5 }9 c6 _8 M& R0 Q
    # 更新路径1 X3 o4 H. U3 H& N7 W' t! L( i
    for k in nodes:
" z. N# l8 A3 {  `        for i in nodes:
# ?6 a* Y- o) g( Q  c            for j in nodes:
/ H& M; M" f$ I9 \7 x                if distances[i][j] > distances[i][k] + distances[k][j]:1 a- I$ {! H& l; T5 V8 y& k4 G% M
                    distances[i][j] = distances[i][k] + distances[k][j]9 R( k8 C- T: {( r% \" L

/ z6 ?6 r. y% g1 k! {    return distances
7 h" w7 V1 o- F" b. u9 Q  A+ p. |
# 示例图(可以含负权边)4 z4 W9 h* ~9 D6 e) h2 B
graph_for_floyd = {8 O' V! y- z9 t7 b& s! E6 h
    'A': {'B': 3, 'C': 8, 'D': -4},
0 @+ ?$ d% O/ F0 g+ q    'B': {'C': 1, 'D': 7},$ |7 T, J& S6 ^- o7 P9 D
    'C': {'B': 4},
# a" u  E' W5 K  m8 r( r    'D': {'A': 2, 'C': -5}
; W2 ~- a) T& X- P% a$ N}( C1 ^4 ^' P8 |6 ]& S. I

* U8 y* o2 Z$ {1 Jshortest_paths_matrix = floyd_warshall(graph_for_floyd)
" _3 ^% z& }, j6 L( f" Y4 w+ ofor row in shortest_paths_matrix.items():9 q8 H) g+ G4 N' L9 l  t. f
    print(row)
* h( I+ r1 D# W% g  a```
, a5 w5 {( {# f% u
- p( H( h1 v5 y( E  |0 l; z## 总结
6 w2 G* Z( j& X2 W- z, Y+ a; L* O3 T; N9 K& G, e
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
+ K2 f+ _* H6 P- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
2 ?, H# k. x% ?9 R/ @" H7 A* _- c- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。4 V4 P8 j; T/ P
( S/ f% x, u* D. ^2 O+ G
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!
2 g3 w- |' f- O1 `
- Q5 {2 r% A- h9 v
9 n9 ^1 _' F- g* H2 w5 X, F. x. [3 b2 Q  [- R

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

回顶部