QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1192

主题

4

听众

2946

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。& ~8 p/ v  N0 y2 r; B
: m5 `; T: f) K' B  Y
## 1. Dijkstra 算法. e" D9 H0 F! x

+ }+ G: ]. n1 K- fDijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。4 F% @0 Y5 O" Q( h5 a
( V* i0 J$ B8 `' h" x
### 原理步骤
' A* x5 m) e# p4 x
6 Y: y. k3 |: \4 Y" b0 f1. **初始化**:# }) p1 ?2 }; P$ _. {
   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。3 ?1 ^9 g( z, h: Q. X0 `
   - 初始化一个空的优先队列,用于存储待处理的节点。: N# G' {% x" u0 B: q

1 }+ C; T# L2 _  i. U2. **处理节点**:
7 I! G0 g' }( r3 f/ G2 s$ F7 T+ f   - 从优先队列中选取距离最小的节点作为当前节点。
9 r$ i& z1 i& h' Y& P6 R' q* j, k) S   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
# @* m1 v# g- i4 J
- y2 O' @) a/ |1 H! a, B3 z' W3. **重复处理**:& P9 V: L6 u. j+ Q, b, h
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。
% p/ j. r3 H0 [5 \4 E3 |" o  q
9 ^/ r3 A' k  q" L3 [+ Y  ]### 示例代码  A6 X) t7 K" v% N) S6 x

% V: s. D7 v! |+ R```python, j% }1 h8 E, F7 ?: y% E' {( R
import heapq
8 {) A- [: R" Z; q+ C- q; C3 @) u" l: R/ j6 A
def dijkstra(graph, start):
% Q# U9 i+ ], ~# F    # 图的表示为字典,键为节点,值为邻接节点及其边权! o8 w; E' C' N( ~% s
    queue = []3 R; |; L+ D! h( C/ l/ C
    distances = {node: float('inf') for node in graph}# Y& y1 @) }( @: ^& t
    distances[start] = 0
8 u+ N" |1 b2 C9 S9 s) `: e    heapq.heappush(queue, (0, start))  # (距离, 节点)# k+ Z+ A1 @7 G9 Y& J0 s
4 ?% Q. f1 z. O
    while queue:' B+ I  y% d. }) s# r+ \! L
        current_distance, current_node = heapq.heappop(queue)+ r6 h2 C9 {8 d7 j! ?
( n( x; h7 G' k- X* M
        # 只处理当前节点的最短距离
+ ?# b5 J( H* V* k! F2 y8 _        if current_distance > distances[current_node]:
, {& C, i; M# }            continue2 L3 D# g2 a) ~; w2 d

8 }# m6 t* d4 h" _        for neighbor, weight in graph[current_node].items():% p6 v2 q% T8 ^9 p5 M; ^
            distance = current_distance + weight. ~( k2 s; ^4 F' W8 A* O

/ p3 u/ Z2 ?5 ~# K2 K$ Z5 d& R            # 更新邻接节点的距离3 Q6 K) @, ~$ I1 E; N' D3 f
            if distance < distances[neighbor]:+ ?+ V3 \# l, k0 f* W
                distances[neighbor] = distance
- Y8 H  B4 k+ n$ |% e/ T                heapq.heappush(queue, (distance, neighbor))
9 P4 F( }; j! `2 r/ l1 O' p0 |! v4 j' i' o0 y" G( ~
    return distances
; v6 `0 ~2 F3 w* K9 `0 m6 S  \
7 u/ v! {  f: D3 L1 O9 b0 _  a5 D# 示例图
& s6 ]# ]' Q& c& g# U- sgraph = {
4 M0 P- E0 f2 L    'A': {'B': 1, 'C': 4},
3 ~- g6 f/ y" R0 f  Y    'B': {'A': 1, 'C': 2, 'D': 5},* A  z( F9 [# q
    'C': {'A': 4, 'B': 2, 'D': 1},3 M2 c" Y2 f: |% f8 m  D
    'D': {'B': 5, 'C': 1},
+ b; E* U1 c/ b}6 Q: z& k/ R! a0 _% z% h( `9 X
" c/ E: x1 B- G
start_node = 'A'
2 k8 _' r! g/ J/ v( Ushortest_paths = dijkstra(graph, start_node)6 s' u) W# Z& f' O! _
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}/ {9 q6 D3 A; r( S
```' r  V# H9 O% Q3 ?, V* S5 q
8 B# A  Z+ i0 F5 v7 `) x2 [: a
## 2. Bellman-Ford 算法
) Q2 t2 B# V; E% N% F( {& o
2 W$ j. b" B5 _. E3 y2 q. oBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
3 J! M$ T7 u6 T" X3 i& r% [
& D+ v7 \9 }, D### 原理步骤1 J2 ~" l% U  `' A7 d

$ m- W2 b* q0 B1 Z" y. o! @' ^1. **初始化**:2 b- F. D; r0 N1 M) L+ J6 d: \% f
   - 设置源节点到自己的距离为0,其他节点为无穷大。
* t& J0 z1 ?2 J) i7 m8 s: w
, T; C$ e1 x" j& a# B1 @2. **松弛操作**:/ k( C" p; \( [
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
+ ^6 V; ?. b0 M% ?; R& T2 Q5 A: p  Z3 p! c
3. **检查负权回路**:
0 d# [$ L4 Y  W: g  e   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。3 `' U) |) o) `

+ r4 v1 a8 `' b$ `; Y### 示例代码4 h  Q9 Z  D  w" h; \" Q
# A! `) L6 M$ e) f. o7 c
```python
0 b& R6 Z) x( q: M, qdef bellman_ford(graph, start):
6 o: Q3 t* B/ ]3 Y$ z) g! d    # 初始化距离$ L$ h5 w& S: P, ?/ @: O! \' j
    distances = {node: float('inf') for node in graph}
; i2 Y0 [3 P# e$ b    distances[start] = 0* p# W1 c  O0 n* t
) p/ e0 ~4 P: k' U
    # 松弛操作" a; G9 c- ^4 G/ l+ n+ Q7 b5 }
    for _ in range(len(graph) - 1):
5 n( Z0 S$ B$ Y& g; W        for u in graph:, z+ S. g) x4 s4 K) S
            for v, weight in graph[u].items():0 F* ]& w  B& |' K# x; [
                if distances[u] + weight < distances[v]:" X. W2 D- J8 I* d  F
                    distances[v] = distances[u] + weight$ g5 n3 I( c# f, t. ~

7 ^) y+ ]+ ^7 D" Y# e    # 检查负权回路$ L, j9 Z5 D6 I) @2 R) e5 f
    for u in graph:$ P" {# G' I/ Y. U! i, S3 f) D
        for v, weight in graph[u].items():
3 I6 E, D( Y  x6 }( B8 O7 r            if distances[u] + weight < distances[v]:" }; O8 l, ^. e1 n, e$ G4 a( g
                raise ValueError("Graph contains a negative weight cycle")
) u1 f* Z* u! m- B
% G! K& ]" \5 o; C    return distances
2 F( U7 A9 |$ S6 S  s' J, T( ]- V" q" |- z
# 示例图(带有负权边)
0 U% E6 b: T' I( x$ Wgraph_with_negative_weight = {# T9 N- e9 g$ \
    'A': {'B': 1, 'C': 4},
6 t' p, M! V8 J. S  W" |    'B': {'C': -3, 'D': 2},1 m- t) x' G$ G& T7 O. [7 q0 }# C
    'C': {},5 E9 n) J9 i, h
    'D': {'A': -1}
# ~" d! A; Y* y5 C  O}5 E7 P1 I* n8 r. y- I# V0 B) |# s
4 A3 \) l6 U5 B, ], S# [
start_node = 'A'3 y; Y. L$ ^  S, h3 [
shortest_paths = bellman_ford(graph_with_negative_weight, start_node)* @- ^, B/ I; e* O4 M/ ^/ `5 J& f
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}8 c( p9 }- ~" S( W3 r: w
```. t& P: ]2 p& w( Y$ L: h: o

# o7 E& X" x1 k# J  D## 3. Floyd-Warshall 算法- c2 k  l8 s, H% r. y
# F( q! D/ b! I7 b# |7 n$ F
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
1 [1 |* D4 z: k( }- u" l; I' m" p3 \$ U  _2 V2 N0 a- J
### 原理步骤6 |; F7 p% M5 c- B+ d8 L! S

0 F% }. l" X" z+ }1. **初始化**:
2 w- [5 w1 s5 j   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。' J& b2 ?$ S2 Y' r
1 T' ]5 @6 ?: \/ R6 L! D& M( e1 G# o
2. **更新路径**:
% V9 Y7 d1 M( E) G5 l   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
' y7 E# o; {# F- r& O
7 P$ d# H$ N: l8 x% k3. **输出结果**:
7 {# L% v! j2 B6 M   - 最终得到的矩阵即为每对节点之间的最短路径长度。
# `. e3 A2 S: e' y# F5 }$ V. v( h% x7 c0 J: L3 q% m* n  C$ W: h
### 示例代码
; g9 a* b  `( a. @4 u% W) O, K, g
, g! A  K6 \% L8 k  _! D0 |5 t! i1 _3 l```python
$ R3 J1 g! k0 F& E: R5 Z5 K: E+ U8 Mdef floyd_warshall(graph):
+ e3 y% o9 r) K4 W' V7 ^1 M. r' n    # 初始化距离矩阵" k( s3 b( _- S; m3 ^
    nodes = list(graph.keys()). Y6 ]; {9 q4 W, A* }2 k/ @9 D9 X- g
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}; j- s+ Q: m6 i( O, G+ A& j
& ]/ G( m9 ^! V1 M5 e" f  r1 v  q2 y
    for u in nodes:
! k4 }+ ]  w- w        distances[u][u] = 09 C1 _: V4 V# @0 s7 _( e# u
        for v, weight in graph[u].items():
# s% p7 f( Y3 f( M4 R# \; F# D% E            distances[u][v] = weight; |8 q; J5 j' N" [* h. y4 L
6 g7 [$ \# k9 z. q5 L' k; L) \
    # 更新路径; T( c8 R5 D8 W# w  k" ]/ J! b
    for k in nodes:( y0 F1 M- f$ T: S8 Z4 g1 e
        for i in nodes:5 y7 F+ J9 ^5 L( o: _& ?) A
            for j in nodes:
: Z. f8 g  T  P" W, [                if distances[i][j] > distances[i][k] + distances[k][j]:
( ^/ J+ L+ y, a" j6 h) H                    distances[i][j] = distances[i][k] + distances[k][j]
2 s- g: N4 [7 O" X, F. ~# Z5 N3 s1 q: t( V, ^
    return distances
0 M, h( A5 L( \% r+ ]5 B% j* a9 P- o" L) y. U0 W
# 示例图(可以含负权边)
6 Q6 K* i8 k! T; C/ \; n5 J3 x2 Sgraph_for_floyd = {
# _( C/ Y0 f2 I4 t    'A': {'B': 3, 'C': 8, 'D': -4},
- W( a" _9 \% k) Q. ]9 [    'B': {'C': 1, 'D': 7},
9 d% U) |8 T. N# E    'C': {'B': 4},
" w& S: H4 z6 l% |; ?! n    'D': {'A': 2, 'C': -5}
7 t* [- v7 y) r# ]& H. r}) Q8 b, z+ B6 h

# y! x1 C  w4 H5 y2 I5 l- U9 W1 sshortest_paths_matrix = floyd_warshall(graph_for_floyd)8 X. x; u, [! t3 `, c* c: w6 `
for row in shortest_paths_matrix.items():5 D* e3 K) R' v9 f: }+ M( x/ e
    print(row)8 H% p$ X, r' ]  z- M
```% u7 j  h7 o% `6 W5 ?+ {* [

# u9 B( |& f6 ]: F4 ^& y## 总结3 C' v; T. V/ H' e

+ R2 C9 G. l/ J. L$ @4 K- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。- m! D" e0 ]6 v
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。$ N8 y( C: y: m
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。0 ^" Q& H( n( V9 c  w

; Q6 N# K* W# s% u" i不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!
! `: N$ |5 S6 A) U
8 v% |5 ]* P3 t) R* l  P) q8 k: l) f  ]: ]( u$ `; O& Z  S) ~
, G$ l+ {2 q- S) ]4 v+ I0 L; k0 W

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

回顶部