QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1186

主题

4

听众

2923

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。. r9 u9 C& o' i" H1 n, Q. P3 T' x
8 Q5 c3 T5 x: f. A2 D; y  i
## 1. Dijkstra 算法1 L! `/ ]$ p* m7 u2 I) W  ]
, P' X  H. S9 [9 d' M) g
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。2 w9 Z: M/ i7 y7 F4 z) ?

+ N1 R% [6 i$ O+ @/ g4 y- o### 原理步骤. @/ l8 y( T* I% U

2 r6 u( Z! P3 X# P  A1. **初始化**:
  ^( v& b( l" p   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。* Z5 d) d  v& [% ^: f2 I5 u9 ]
   - 初始化一个空的优先队列,用于存储待处理的节点。
% U  w1 U& M! a) O& }
6 Y" Q& X7 y0 S* D1 i6 m+ {2. **处理节点**:
" i- M% m1 |/ l  Z4 h! `# {   - 从优先队列中选取距离最小的节点作为当前节点。
- z5 P/ m  F" d' L! Y   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
2 Q! l; ^" T  V% |& p& ?/ I
1 U% F* I4 u3 J$ F* d: {% f3. **重复处理**:
% V! I+ c. w) W9 Z& u* F, T3 Y1 d% h   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。$ [1 G2 |) ?9 @" P4 r
4 b/ e- q% j7 K" P- Q& Q/ u+ A: C: |
### 示例代码3 f( T: L4 l: C
$ [6 p, `& F0 Y' \5 s- K
```python
& [2 Z% k9 a8 |6 t$ u8 Timport heapq; X# r+ r* l! d9 H( Y

% Q1 c7 M; A8 O; adef dijkstra(graph, start):
* A% w9 N( s( P0 Q    # 图的表示为字典,键为节点,值为邻接节点及其边权) f! f1 `0 R7 s. ]7 ^* r; i4 {0 \
    queue = []. r! W; {5 U8 f7 t$ P
    distances = {node: float('inf') for node in graph}0 [) N. {* f- B$ a/ G
    distances[start] = 03 p1 h# c1 R) s+ q4 e3 d. k
    heapq.heappush(queue, (0, start))  # (距离, 节点)& `8 p* b$ U  g6 s+ u+ \
5 F! E% e, e' H( x, W
    while queue:' ]& M1 R* T7 h1 O8 ?
        current_distance, current_node = heapq.heappop(queue)- B( X) t# T$ a8 c/ e
& q  |0 ^1 b- D3 \6 u( O. w% ?; k
        # 只处理当前节点的最短距离
3 Q) G; A9 F( S. b) `/ W- m        if current_distance > distances[current_node]:$ }( k8 P; S; \5 e" L# Z3 k: d3 P4 d7 P
            continue9 q* X2 t0 M0 c6 G9 y
8 w4 `/ p1 X! M6 _
        for neighbor, weight in graph[current_node].items():% p  U) s% F6 P0 ^/ D
            distance = current_distance + weight8 `2 z; u' h# w2 w3 h6 Q. w2 ~4 t; g

* }9 h/ ?. P+ {            # 更新邻接节点的距离
% v" j8 A( ?8 T- o7 A6 _            if distance < distances[neighbor]:4 Y( m) W+ m' w2 q0 U
                distances[neighbor] = distance
( E# y- {! `; r* Z3 w8 _9 S: U                heapq.heappush(queue, (distance, neighbor))- m9 Y3 O& `' Y

' s1 k- f' D! v6 t    return distances
6 W% a$ [* r4 u$ d
! b* i! y, x7 i8 {/ d- |# 示例图! w. _5 B9 T  ]
graph = {
; g7 }( i* F8 g: W    'A': {'B': 1, 'C': 4},
* T, K' L2 ^: N$ _, K4 V9 ]    'B': {'A': 1, 'C': 2, 'D': 5},% v2 R% e, W+ s2 H9 T3 b, a
    'C': {'A': 4, 'B': 2, 'D': 1},
; d$ |4 a# @: T    'D': {'B': 5, 'C': 1},' z! ]- C8 _" w
}# w7 F* f) i: @4 e( f+ e
% u2 b1 [3 u2 Q, }& R- _, B% R5 |! p
start_node = 'A'$ K* h) J& e, S" v& X
shortest_paths = dijkstra(graph, start_node)& i4 V* D0 i* _6 U
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
. X5 `+ z* e2 u```
  g. A; R& J% Y; l- ?6 K/ y8 ~! b1 m' z
## 2. Bellman-Ford 算法
) I1 A! O3 t% h2 ]+ @5 Z5 k6 B8 d5 @
3 ~% {2 C6 q( o' CBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
8 s* T8 X, G  _! B! S. W, P; z( ?3 F, u( J+ t, H
### 原理步骤2 A! Q+ n% O2 ~; _
5 Y6 s# j+ n9 e' w5 j4 y
1. **初始化**:% ~! Z% p' R( T) b- K1 v4 q- o9 Y3 q
   - 设置源节点到自己的距离为0,其他节点为无穷大。
9 x7 @% D$ U% z2 b
$ V  H+ Y, _1 V2 j: L. _2. **松弛操作**:* r' E6 ^+ @7 t- ?6 \3 {
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
* d' W2 W. g7 E& f* A7 J2 x$ i  a5 f5 g+ l' B4 U
3. **检查负权回路**:+ K* P8 Q/ l) R) _) j; T) ]" ?$ G
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。: |# s- y8 j) S

8 h8 G' r9 P/ C+ F0 F2 h+ Z6 w- f### 示例代码, ^- C0 M1 ~# B8 H1 Y
7 L* J. {  d( a- p8 a, f- |
```python
9 S! c  b( Z, ~5 ~& jdef bellman_ford(graph, start):
9 h8 i; \3 K* a1 Z2 W% P    # 初始化距离
8 i! H) _3 |" e8 P% A" |    distances = {node: float('inf') for node in graph}* V- S) s$ q# Z6 a% F  F: K; C
    distances[start] = 02 t2 `) V8 N( X+ s, ]. D( z1 }( p
" P* H! H3 N$ o1 w/ f
    # 松弛操作# N/ R" G9 w) g# h% T8 l
    for _ in range(len(graph) - 1):
1 d5 p& q5 S1 r! X        for u in graph:
: Y6 U# P" G8 a5 R            for v, weight in graph[u].items():
& |9 h) I# N+ D0 B/ }0 Y8 v# g                if distances[u] + weight < distances[v]:) t' F, f0 M& T- A7 r: ?) p
                    distances[v] = distances[u] + weight
) c  s" k- }/ [& r0 e' ]5 P' ~7 e( E% |! R3 A3 U3 n, ?. B
    # 检查负权回路
3 {+ S& |, g. R7 `. t" ?1 Z    for u in graph:
7 H6 j, [. e8 O        for v, weight in graph[u].items():' x9 ]4 B2 A  S  @$ j" o
            if distances[u] + weight < distances[v]:9 y+ c1 ]1 w9 j3 D5 ?$ W, T. e. D
                raise ValueError("Graph contains a negative weight cycle")1 U/ l# H  b8 L/ M' e1 }3 n
9 E0 S* `, L/ V. u& B
    return distances6 {. r3 U0 P! u

& l9 f$ x( }* u# S; \! k0 a( w# 示例图(带有负权边)
# c' Y8 `3 y  Qgraph_with_negative_weight = {. l9 K- N4 {( ?0 q) H$ G  b
    'A': {'B': 1, 'C': 4},
" o: a0 y; M* Z0 R* e4 o! s& n    'B': {'C': -3, 'D': 2},
1 \9 G8 I$ R. Q6 e    'C': {},. C- k' k3 e2 W  q/ y* ?& e
    'D': {'A': -1}! H9 K$ X" K$ u* D+ a
}" x1 n- a& ^5 }# J

6 Q4 y. y; |2 b( Fstart_node = 'A'0 u  x4 v# k+ D9 O/ A
shortest_paths = bellman_ford(graph_with_negative_weight, start_node)) w7 D* }( T5 Y$ I" |+ \- [
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}. {3 I8 X/ {4 f" @0 d5 V
```
& M7 t9 b9 ^0 z% V9 B4 ]
7 j, ?! P0 ^9 T2 W6 n5 w## 3. Floyd-Warshall 算法/ v/ n2 [: ]5 s  z4 P; k! a& l
: x6 k4 k2 d# ?; m6 S
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
2 F5 n% }# X. U0 z& |
2 G2 ^+ w/ n# {### 原理步骤! i% d& F" N( |8 M8 L" e9 `' J. c

0 c( j/ U- f8 s% v/ S5 _% w1. **初始化**:' n  F( @" h( I7 U. {  ?5 r4 S
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。
7 L' W% @  O9 R! f& F6 ~& F7 C& _$ i* B) s; I/ h( u
2. **更新路径**:
2 [9 u7 X# ?. s( x! @* Y   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。3 x. q- U+ v/ B
! r$ f- v* J) B, Y
3. **输出结果**:9 w% Y/ N2 i) z* _7 _
   - 最终得到的矩阵即为每对节点之间的最短路径长度。
, N  K/ b7 d7 B# x5 H
4 u' Z' t3 m' _' I9 [### 示例代码
  }9 W1 v& D- `8 ^- n4 A
, z) H* \4 g7 ]1 ~9 f' H' X```python7 F& t( F; Q% }6 l
def floyd_warshall(graph):
) e9 Y! ^( G  e1 q    # 初始化距离矩阵4 Z3 a; {  g* d9 I
    nodes = list(graph.keys())
9 D  S' s) e, E0 G    distances = {node: {n: float('inf') for n in nodes} for node in nodes}
3 t& j9 }+ ?6 l/ ?0 }5 Y) U
: _* |$ O# p# L# }8 E    for u in nodes:
0 t% h* X5 U+ n, c* \. ?0 T0 G        distances[u][u] = 0
  A$ S* Y; j" G        for v, weight in graph[u].items():; u+ k* P" E- J, z" J9 S9 e  b* Z
            distances[u][v] = weight- \5 T4 g' J& q/ T0 U- s* N3 p
, x5 y, q" n  `* u0 N
    # 更新路径
: s' y! u; o8 R' K5 f! [7 G0 f    for k in nodes:% z  a4 D5 l8 L, U$ A, ?4 y; A
        for i in nodes:
  C1 Y4 r8 {$ o% j. F1 i8 V/ f            for j in nodes:5 ]3 Y; I4 D3 U3 R; z
                if distances[i][j] > distances[i][k] + distances[k][j]:/ r: F+ h& Y3 H' f+ m' j/ z$ A6 Z
                    distances[i][j] = distances[i][k] + distances[k][j]
' }4 x) D. P! I/ n& K
% F7 G: R/ m" {- D6 N# h9 g    return distances5 @6 G0 A& x9 w5 X+ f; Q" y# j% G

$ W( O+ n6 w3 f2 a, m3 q; ^  C# 示例图(可以含负权边)
$ o( @# d. s: _graph_for_floyd = {* c& X, N  e1 a$ V+ h+ z
    'A': {'B': 3, 'C': 8, 'D': -4},
8 D" O) z( Q' l: C3 j+ f5 [    'B': {'C': 1, 'D': 7},0 o8 c  A- y6 l
    'C': {'B': 4},
" e7 Z2 H+ d, ]8 Q& \' x  o% n    'D': {'A': 2, 'C': -5}" D) e" t, j9 W! r5 A6 H4 c
}3 Z0 E/ h# Q2 ?* L* [) v

3 x! O: `. U, F# f0 fshortest_paths_matrix = floyd_warshall(graph_for_floyd)* x/ [  R4 Z" A. z/ @+ U5 ~8 R
for row in shortest_paths_matrix.items():
$ C" T& F4 g' H9 `) P1 ^, t    print(row)5 P( H' O6 a7 D! z! W9 _
```
0 S4 G5 H0 ]: L$ {8 L3 q% B" p' T: ]
## 总结- z8 `1 a+ |8 `
1 S5 t9 Y( c7 D: k
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
% q1 H+ f; x* ~0 Q; e8 z& Q. ^! l- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。# a9 H' T% i  }3 T
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。
' B5 d2 Z" t- ^1 }$ g
9 |# w' {  H% F% E不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!3 s1 R& G# M& R
3 n- }" Z# D& |
5 c/ L! t( k1 O5 x4 s* p
, \: Z6 b- V7 @& {7 j, ^% O3 y6 j

最短路径算法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-26 14:20 , Processed in 0.711421 second(s), 54 queries .

回顶部