QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1175

主题

4

听众

2823

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |正序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
2 Q" `$ B1 |- p. K# x. U' W
$ h5 A* V& C) b$ l0 x1 B* ^* E1 P## 1. Dijkstra 算法
1 W) G% v1 I) _1 x5 z5 G7 ~# D( _. s" T7 U0 }0 A
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。
+ B- e! j- L' p+ ^0 R! s% T3 X# f* ?9 ]6 D9 d( y
### 原理步骤
/ g6 c6 x6 ~. D& v" J7 G2 i( @* A- I2 T3 ~7 x8 c: d
1. **初始化**:
4 |+ m. _" {* n8 X% d. C   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。; g1 j. w- Q8 F" p* X  L5 i1 ^% L/ {
   - 初始化一个空的优先队列,用于存储待处理的节点。: K5 ]% j- s: M; d/ R# N
; Y6 j9 F8 a! y) c( V; Z
2. **处理节点**:- ^$ ^* v6 p! j9 t5 h
   - 从优先队列中选取距离最小的节点作为当前节点。
6 x7 ~! ]! S/ D& L4 w8 l/ n   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。$ W+ h" {9 P4 K( k7 U
: G& k% Q" b  ?2 Y2 ]5 c
3. **重复处理**:+ S$ \; E( B( C" j1 P( _
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。
. q0 Q1 z9 V) j3 w/ k/ `2 q
! u7 U( ~" i) K+ w! H, t& v### 示例代码- ?) G; K7 O/ z& Q5 j7 v
( h1 o3 R, @+ S- b3 [8 O
```python
* T- Q* P2 n# ~" i# h  x$ p$ cimport heapq
: b$ ?# Z) G# p% R: W1 m$ N8 M% h6 r8 ?
def dijkstra(graph, start):
. v; o- L4 {( k: L: A  [8 B    # 图的表示为字典,键为节点,值为邻接节点及其边权
) Y9 R4 L0 A7 m! Z; g3 ^3 B/ P    queue = []
% v& ?& L5 V7 ^5 p) E3 p4 A' a4 n- V    distances = {node: float('inf') for node in graph}- F. }2 @2 S0 D: W: a9 h
    distances[start] = 0$ i* o, F* u6 Y# ?5 s! m8 T. G
    heapq.heappush(queue, (0, start))  # (距离, 节点)
3 i- Z$ x) X7 h  q3 F' V& q0 U5 z8 V2 _1 J! S& {
    while queue:
; {5 J' M3 ?+ V2 M. r# G( q8 B$ _        current_distance, current_node = heapq.heappop(queue)& D2 u* V& \: \6 j, |' W
5 ]7 L4 u: P4 m' v/ [4 b& y1 }
        # 只处理当前节点的最短距离
1 U; M' n* A, Q/ a; U! s* S        if current_distance > distances[current_node]:6 t% {; b3 v% Q  d. U( ^, ^  G
            continue
" _, T! p$ u$ ~4 M. t: Y& M
/ |; a9 I9 }7 n$ b        for neighbor, weight in graph[current_node].items():
9 G0 e5 A; z. ]( d9 [+ {) B            distance = current_distance + weight/ K, ?8 H  j1 O' }# u

6 S3 g% S8 w5 L  h. x- d9 Z" o            # 更新邻接节点的距离
, k' e" i0 k7 f# R* h: ~5 P            if distance < distances[neighbor]:
9 }6 l' z4 N- N3 L5 _( u                distances[neighbor] = distance
. P* b6 v' M. L. `7 `- y2 a                heapq.heappush(queue, (distance, neighbor))7 O& |5 e* q: ?. O* Z9 x

6 I4 t$ H& p8 W' q9 |9 Z    return distances- V% Z- |  p2 z2 f- e! R
; ~. y% O  U, x! j! I
# 示例图7 U3 ^/ P3 h: O
graph = {
$ d+ _& ]( q0 A; m2 O    'A': {'B': 1, 'C': 4},
8 E( z. V  H: m$ x    'B': {'A': 1, 'C': 2, 'D': 5},) R. q: \' M' |
    'C': {'A': 4, 'B': 2, 'D': 1},
/ s# n. ?/ \' b/ l) ]* @    'D': {'B': 5, 'C': 1},0 {9 c: ~3 E4 g8 ]2 l
}
. R+ g% Y! w2 X0 u9 l/ T
6 W. c  _: X$ l9 t) \2 bstart_node = 'A'
4 P$ f" B) C3 C* p* \1 V6 f+ Fshortest_paths = dijkstra(graph, start_node)
7 l  q: K/ p, G1 pprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
  _) A( u! J$ q, y% Y0 Z, u```
+ Z  }' H  P$ H2 Y) `# c
' I8 R! l  Z' F/ S4 p; u0 A: U! X## 2. Bellman-Ford 算法
+ R6 ~. B1 f/ O1 H
7 x; h& D- F0 |$ m8 j2 b7 pBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
) a- {' x4 ?1 y: M. q" ~4 u5 o- a1 t
### 原理步骤
& N6 G- f2 C$ l
; {0 X$ x' ]3 I2 q+ a- R- J. h1. **初始化**:
/ H$ \) ?+ r7 p2 F+ N( w# E$ Y   - 设置源节点到自己的距离为0,其他节点为无穷大。! }6 `: F* F& q

' X, j" A% Z( L2. **松弛操作**:
6 s" X; N+ m5 P1 O( j. K   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。1 j5 h" Q4 g- |  W
7 P& a5 t# I% e! H& v
3. **检查负权回路**:- O( i4 `5 l( ^
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。6 W2 g* x* T( ^: [) B
; o% E  Y9 R$ o9 j9 p, v
### 示例代码* X7 Z- {; C; {, V3 {! w3 D2 s3 ?

4 i) X& X  P( r. t# W8 H! L```python$ m! x1 A* A, S, D* M
def bellman_ford(graph, start):
! x) |8 h, z! J4 }    # 初始化距离
( n( T' g. B4 c$ {8 u    distances = {node: float('inf') for node in graph}8 W. f$ @. r+ h" e$ e
    distances[start] = 03 ]& b; \4 P- G0 \* x% d& u2 I
" D% U' J4 H; F% B
    # 松弛操作3 t; u1 H- m- f& i% g5 R$ @
    for _ in range(len(graph) - 1):
0 n1 z' v4 V: ?6 X" ^+ D  B        for u in graph:
# ]* h; e% a6 X2 x            for v, weight in graph[u].items():$ p* a5 N5 b' e! {; L! n, C
                if distances[u] + weight < distances[v]:" E) c! A2 e' ?+ H, o
                    distances[v] = distances[u] + weight' u5 r4 g& Q1 r1 o+ U3 ~, d3 g
- S$ w# b/ U* y' A
    # 检查负权回路
  f2 a# f+ ~- F& J& o3 r, R' y    for u in graph:/ e5 \/ e2 J+ p- `0 G
        for v, weight in graph[u].items():; g% `# V" A9 A' S
            if distances[u] + weight < distances[v]:+ g! y+ A! v- H3 H' o7 F7 G
                raise ValueError("Graph contains a negative weight cycle")4 W# ]8 ~  E; ~& X
8 m5 _/ M" X0 ?: Q; m+ _
    return distances) E! J2 X: s/ }( V& G

# g& m0 `- I+ e( U  D6 W# 示例图(带有负权边)- k$ g. q7 I8 `  D$ g. C
graph_with_negative_weight = {7 Y8 m0 ^' w" t
    'A': {'B': 1, 'C': 4},
$ Z2 ?8 [: x" t    'B': {'C': -3, 'D': 2},5 y% g/ n3 F" ~, I  w7 {- S# g
    'C': {},7 G5 ]' \, z3 Q5 [0 R4 b
    'D': {'A': -1}3 B' F3 q9 ~/ R2 U% o5 f# E
}5 \5 q7 d. v* ]

9 W& j5 h: K9 nstart_node = 'A'
( f: G" P0 f" G( m& zshortest_paths = bellman_ford(graph_with_negative_weight, start_node)
4 j1 _( [5 [! Wprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}9 @* [4 o0 F: v, ?$ G* a9 T
```
4 v1 K* f2 d3 L2 W) n( Z
" Y9 s8 f/ `& P, v: K+ B## 3. Floyd-Warshall 算法
! O8 x3 d- M6 d9 x
# G) R+ ?& |+ ~2 j7 V' XFloyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。- K9 e2 i. R1 D/ [( h
9 T2 a, \1 A: N6 F
### 原理步骤
, ]0 @6 M4 {8 d7 a0 B1 Q- T
4 b% q' X2 f) A  I1. **初始化**:
* U: K& Y, r( E' p+ `   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。& {7 w' G4 W+ a4 N+ V

8 ]- j7 g1 x! N3 I* _. h& s2. **更新路径**:
/ o) i- z3 ~5 T0 ^6 b1 q   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。% P. C4 O6 u/ X3 x8 A- ~
* L/ x) v& O, `/ `9 [/ T; x& C
3. **输出结果**:
2 h3 k, c4 j% |+ s   - 最终得到的矩阵即为每对节点之间的最短路径长度。/ A: [$ S: O$ j. T. ~

* ?: ]3 ^: `0 _+ F$ O! K& u9 U### 示例代码5 K( s/ y' s5 W9 F" Q' A$ Y' a9 }
: r! E1 q. F5 }0 h
```python/ U; Q9 k% h3 v/ ^1 d
def floyd_warshall(graph):
4 i4 V* e* W8 [4 g' _    # 初始化距离矩阵7 M" x2 J/ ~- m. `2 m9 S
    nodes = list(graph.keys()); G0 U$ @0 f- I" f2 \
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}6 x. b: G0 G8 c
$ `% u& F2 y% ?2 ^; ~( T4 g, x
    for u in nodes:5 u! H3 l* Z: U0 w
        distances[u][u] = 09 i1 Q5 {- ^4 Y, v$ I* v+ a
        for v, weight in graph[u].items():" `+ ]2 P  `' v. c+ ], w6 ^% U- [
            distances[u][v] = weight
# F! d7 P" G+ n0 E1 E+ \& C, T
9 ^2 i2 u  Q4 ~% ~' g$ b8 z    # 更新路径8 M  m$ `# r$ s. @! D* `7 r
    for k in nodes:
+ Q' M3 R* H7 n2 C; Y        for i in nodes:
# F% x: ~% ^" G: c            for j in nodes:
' O5 }; R7 C0 a' U                if distances[i][j] > distances[i][k] + distances[k][j]:6 p  e% F4 Q) t# x
                    distances[i][j] = distances[i][k] + distances[k][j]
; @% g% C. T+ W9 ~
0 n9 S% `8 J$ u# e    return distances8 L7 P& x) B: w# U- R
+ F. _% ^4 r) D# i  ~
# 示例图(可以含负权边)
$ M  H( b7 `& F, l, F" Bgraph_for_floyd = {
( v# I5 K6 n  X2 q% E+ p    'A': {'B': 3, 'C': 8, 'D': -4},
% z+ v1 z( A7 A: f+ `1 }    'B': {'C': 1, 'D': 7},! w  F, |) E% p" F# ?  a# B
    'C': {'B': 4},& A7 ]2 i8 _# O, k9 L8 h* n. |
    'D': {'A': 2, 'C': -5}
0 P' y# g2 e; e6 k( G) ]6 J}
5 ~$ d8 q; @; ]& r2 y( x( I: k4 k+ E5 a; X: n2 i
shortest_paths_matrix = floyd_warshall(graph_for_floyd)$ X/ l! p, |3 }! ~0 O. \0 \- {3 t
for row in shortest_paths_matrix.items():
1 ]% g0 `! [3 f1 |    print(row)1 u& T. C# G" _
```
3 R9 D  O' I7 i1 x9 S5 m5 C+ {7 Z5 |, i) y6 n  _! W: a  }% n  j
## 总结# p4 C1 ^% p/ N6 i4 T% R
6 i! z  o) A8 O1 z
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
) l1 K/ p% _1 [1 L. n- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
7 R" H) t6 e/ V4 `1 H! E- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。, i' a' }; M3 E9 M5 X

1 |. d; L5 \' Q: |不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!, B5 a- y8 p4 A* ^+ _' A$ u
! \1 u9 F1 Z+ N% K$ |8 L* i

1 a3 \* n+ S( t5 r5 e" x/ s& h* {) ^! O' X

最短路径算法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, 2025-7-22 03:28 , Processed in 0.428802 second(s), 55 queries .

回顶部