QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1198

主题

4

听众

2978

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。/ U- j) u4 t5 @# n1 U! j) l
2 @$ A  N# S% q1 E" W
## 1. Dijkstra 算法
3 O' h& g" o- N$ C$ y" \( S$ o8 e" I* }( W. j( P  O1 L
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。
1 @( B: U& n7 b# x" v& x" ^- o9 a; a
### 原理步骤
! z6 G9 _9 `$ t: S: [2 d/ M5 }/ c& ~6 C  S- n7 }
1. **初始化**:
0 W; m: S! t2 s# X) r0 B& X  o   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。0 x  p. g" P, o8 ^. V3 a
   - 初始化一个空的优先队列,用于存储待处理的节点。$ p  Z  u: W4 _. a3 k/ Y3 y* q
5 h( N8 Q8 T! z
2. **处理节点**:+ A% [( r+ Q) r5 |: _
   - 从优先队列中选取距离最小的节点作为当前节点。# H5 E- p9 k" k: Y$ j3 f3 _
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。$ T- u. [! k0 d  f3 T5 \

+ [. e+ z9 u! J2 ^3. **重复处理**:
5 \/ `" J% g3 ~  _. R  r   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。; g# Y2 w5 K! z" @3 K( B& M
4 n2 R2 `* q: q
### 示例代码
! p3 w( g: D, L3 _$ [7 h; ^) v- a3 m8 V, ^
```python
/ x; C) S3 J' O& Z6 y' zimport heapq
9 k9 r0 {( {( O' k
' V' y" Z* |& o2 @0 F8 _def dijkstra(graph, start):
" T$ `, `' g* m+ C8 `' D+ `/ @) A    # 图的表示为字典,键为节点,值为邻接节点及其边权
9 [/ i6 |* f# r7 m& m6 `    queue = []' h: E! f2 U1 S. a! c) s$ T
    distances = {node: float('inf') for node in graph}0 D& _+ y; q* f8 w3 ^- z: o4 ^
    distances[start] = 05 q( }* ^8 y5 E8 p! m0 u) d
    heapq.heappush(queue, (0, start))  # (距离, 节点)# u2 ]+ H+ Q( l0 q2 g6 m9 `/ I# A
. r/ B1 G7 ^  F+ P# u- J3 p
    while queue:
+ n5 ^) S* X* ^: i$ Z+ v5 T        current_distance, current_node = heapq.heappop(queue)* G: j$ K2 l4 h- n6 c! V8 P4 q( y; @! o' L
2 M0 U2 D- ]7 w' _. j
        # 只处理当前节点的最短距离
! J1 |: i+ X' {% @& Q        if current_distance > distances[current_node]:+ }; b6 n2 o, ]# D6 ]" n* n
            continue) T( m/ J1 N5 j1 m
# O( l5 a* X, U* x# H* ^& J: J1 V3 P9 z
        for neighbor, weight in graph[current_node].items():# C6 ^  i, }6 B5 U7 l
            distance = current_distance + weight
: _; c. u1 H; P4 j. g9 @2 r* C
" f# `% P9 @- I, j* ~            # 更新邻接节点的距离
* \7 A) V% a6 V2 }+ P            if distance < distances[neighbor]:* v& L) X# f/ m% ?
                distances[neighbor] = distance
  T# q: `! S$ R4 v. N                heapq.heappush(queue, (distance, neighbor))
, Z" n8 p) L; p  q
: ?1 q1 R- i7 a$ C; P  {    return distances$ I$ V5 i3 ]; f

9 M, i1 [" o- o+ Q+ k+ P# 示例图
9 W7 p5 s' E+ M7 {# y$ `graph = {2 z  f: U% ?% N
    'A': {'B': 1, 'C': 4},
1 X3 h) \; @* T1 J8 M8 k    'B': {'A': 1, 'C': 2, 'D': 5},
! p0 j7 z+ ~' w* F3 G; H    'C': {'A': 4, 'B': 2, 'D': 1},+ n7 U' w+ L% M4 d# V! t' |* R
    'D': {'B': 5, 'C': 1},
, _2 N. L( T+ G7 j3 d}
* F9 c- j+ M5 j, B
! ~1 |' V# D2 j) cstart_node = 'A'
  A# V+ X/ A& g9 q; y! Eshortest_paths = dijkstra(graph, start_node)
8 b6 A- z6 k2 I; F+ Pprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
5 i9 y' X2 j  T( v0 A8 ^```
3 k/ [4 h! j/ w  q! C% r
! M+ R/ `/ Y  h0 R$ a4 v  [## 2. Bellman-Ford 算法
/ D# x3 M! C( W  z; C( Y2 m: \' b) b% @7 m% J- }0 h$ G6 l& r  U7 ?8 I
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
3 f- a) r6 r' A* J
4 [9 C0 \3 t; X### 原理步骤
+ u# S$ _+ L6 p& Y3 T2 B) v% b: C, ^* }
1. **初始化**:* @3 k* j6 X- e% d
   - 设置源节点到自己的距离为0,其他节点为无穷大。' U! C; |4 j4 N* b; u6 W( e* }5 T

, H% E5 w7 {% B6 x) Y9 b: {# F/ b2. **松弛操作**:
. J. x( O, L+ o6 ^, x$ |   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
" D6 H6 j5 O8 [4 ^9 }' {% K# |, O; ~7 K  s$ b
3. **检查负权回路**:) A$ M3 K% \- Z! J0 \
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。( q- {# f+ L4 T) M: [0 e3 ]* \: s
% s2 k$ N/ I/ S2 ]1 i* e9 H
### 示例代码6 n5 B& {' N% d2 L
7 {" q+ N+ C0 g- e+ s
```python
2 _6 a  {7 U- @5 k# M; y4 H3 I: idef bellman_ford(graph, start):# {/ Z& J8 H5 u! n
    # 初始化距离
( d* t) h  F; @- @    distances = {node: float('inf') for node in graph}1 M' @0 c9 g, \3 e5 v- n! t7 }
    distances[start] = 0
. ^- j9 H4 F, [$ f( D
5 E- w! V( q! j; x3 t! v7 m    # 松弛操作( b2 s$ c: O( a. F
    for _ in range(len(graph) - 1):: q. F! h; @6 x
        for u in graph:- P  I; C7 H9 X1 I$ e' w
            for v, weight in graph[u].items():* z6 x* ?" b5 G9 u4 K- i
                if distances[u] + weight < distances[v]:
- w: n5 B3 b7 w: E5 V' }                    distances[v] = distances[u] + weight
- z- g6 n  K: Y6 T! K$ l# }+ Q& j; U3 q& v5 ^; {# \, r
    # 检查负权回路9 f3 J5 U# y; Q8 V) a2 `) N
    for u in graph:
: ]6 U0 a+ P  o        for v, weight in graph[u].items():
8 i: h' k3 l" R- K" i! J            if distances[u] + weight < distances[v]:. w+ b9 n' u2 h+ e2 w- X
                raise ValueError("Graph contains a negative weight cycle")) _& |1 b+ z; U; }( y

  s. Z( a% J* L* `    return distances
: k: l, i+ G7 {$ G7 f7 ^$ G: b; B: U& e0 K
# 示例图(带有负权边)
; t3 `- w; |9 X0 f% `3 Lgraph_with_negative_weight = {
( G, W  w8 k! g0 p/ M    'A': {'B': 1, 'C': 4}," h: U' `; O! H; y- l, G" T/ g
    'B': {'C': -3, 'D': 2},
% ~% B# J3 a' E$ u) v    'C': {},+ @- T2 f& s  |) Z3 C3 g$ Q
    'D': {'A': -1}
3 p0 k8 T+ u% m7 s}: ~0 a: ^; ^) |# Q: Z# n
- I9 Q# [9 V) F! }- ^0 ^* B1 `/ R
start_node = 'A'
: Y8 b0 g' u' p( L5 C, hshortest_paths = bellman_ford(graph_with_negative_weight, start_node)
& t! ~" j7 ]2 ?+ Rprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
% t9 g- v: e- b4 a! q+ @/ d```8 c* A% B3 |$ I' X5 U. [
' g+ b9 q4 G0 _) `" n
## 3. Floyd-Warshall 算法, n3 G9 J1 g3 [; B: m2 x5 I( {  p6 R
. ?5 `% w- \) [( z6 q
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。' a' u( x3 z$ J5 s' j( r

5 i1 b' s6 k3 ]3 @& d### 原理步骤
& f4 \$ G% B" F9 |0 W5 ]6 w+ T
4 m9 e; P3 D/ g: |% i1. **初始化**:+ J. `) E* H2 L# H* y6 Y
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。2 J( _/ f) `8 u8 J% d& \; U! }# D

3 V  ^- d% @% G5 B: @2. **更新路径**:& x4 |9 X9 L0 b1 P
   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。* V7 g8 F( H" T2 ^+ z1 ~7 a  y
0 ?$ L8 ^2 P' P4 d" _
3. **输出结果**:
( u# ~" x; m7 O* @! Y   - 最终得到的矩阵即为每对节点之间的最短路径长度。
' n1 h4 w$ w0 O8 z, v6 L. q; s3 Z% h' ^  a) Z3 y, Z
### 示例代码8 i* F8 C! g6 t! ]9 Z% C

) H/ _* Q3 R4 z; R4 [2 {```python5 L8 C5 ^4 \, h+ {7 S  v
def floyd_warshall(graph):, Q9 _) A. @( `/ P& J
    # 初始化距离矩阵! ^7 h& q( D% u2 C
    nodes = list(graph.keys())( o& E- A9 O7 u4 Z7 n6 H
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}7 s. \: e# ^" x; j' ^2 K- B

- E3 I) b* {9 w; ~9 `    for u in nodes:; Q8 e1 w* M8 D4 s* V* f% V; |
        distances[u][u] = 0
( E" A# i4 V$ c$ N% \! B        for v, weight in graph[u].items():
7 g9 d9 A- S7 @- p            distances[u][v] = weight6 ]- s: c8 V! x8 N( ~2 p* h# J5 e
, U* c' F& Q0 Q
    # 更新路径2 S5 F# K- I( n6 B' Q( f
    for k in nodes:, H* |, L( T; Y
        for i in nodes:4 q# r) @9 j" g5 }/ }
            for j in nodes:; v- z8 y! ]+ Q2 j2 X% [3 B5 Y7 |
                if distances[i][j] > distances[i][k] + distances[k][j]:
. n1 o$ N. e/ g; k9 v                    distances[i][j] = distances[i][k] + distances[k][j]; z. C6 o+ q1 z, O5 F. M: ]" h3 l
0 H0 J6 N" Z0 ]
    return distances% Y1 Z4 R! Q) g

$ v4 w. P. Y6 s/ T  D+ \# 示例图(可以含负权边)2 N7 q# S  k3 Q1 _8 l3 X
graph_for_floyd = {4 K1 r6 q1 ?2 u3 S2 {' j( ?
    'A': {'B': 3, 'C': 8, 'D': -4}," Z  F* w7 @1 R+ o
    'B': {'C': 1, 'D': 7},  H2 e6 R! P0 c4 F/ o% p
    'C': {'B': 4},) b$ Z8 e3 k: n9 U" x
    'D': {'A': 2, 'C': -5}
. v+ D1 i- i! g; R6 N}
* o9 [7 J/ F* Q- ?. f% R/ w) Z, c$ a
shortest_paths_matrix = floyd_warshall(graph_for_floyd). J/ i' G( ?. Q. O( {, W
for row in shortest_paths_matrix.items():
* \; b  m  j4 j, g; Q- B    print(row)
) f" d7 Z/ D9 U, d3 z```! E7 V# x8 X( e
5 m1 e2 ~1 z( e  o& o7 E# j4 F
## 总结* y4 g1 Z6 Q3 p4 n  o. Q5 ]
' p6 a" X7 `/ [/ `+ U# z
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
# }  ^, i! |: w. d. X5 J- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。/ T4 E* B1 ^# {4 h9 a2 Z. H
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。
7 m; a9 t1 [4 G' W' Z! x9 Q; J, a* t2 |) @
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!& P9 Y1 Q" ~4 g% _2 y4 q
& z0 f. @6 Y* W' l* Y

# O$ L4 [9 `4 A7 @* \  W0 z7 u/ P3 ~
4 P. y5 C2 ?# ?( ]% s

最短路径算法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-10-11 02:10 , Processed in 0.372817 second(s), 55 queries .

回顶部