QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1189

主题

4

听众

2934

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。$ n$ R1 Z7 M0 c. T; r4 e4 i

5 V0 o* m$ d- ~. _  R2 b+ C## 1. Dijkstra 算法
. K8 ]9 o& Y" F1 q! D& w: |& s) L  T* D
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。* u0 T, G3 R1 C1 \' \
9 d2 i! O5 ?! j; A( j  U
### 原理步骤
* K/ ~1 p6 P0 t; L
9 i6 T: M9 Q+ v) w# g/ }5 z1. **初始化**:
' J8 J! L% M7 N6 z/ R   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。
& ?* a: x0 C3 t   - 初始化一个空的优先队列,用于存储待处理的节点。
. E  U' {4 }6 v) n- g" u/ i+ l. i5 i- M) o0 m5 N0 M- ~
2. **处理节点**:1 u3 d2 O& U1 g& }- M+ H& z
   - 从优先队列中选取距离最小的节点作为当前节点。
7 i# ?! m8 n% }" K+ ?   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
) h3 X5 S( R% R% P. \0 ?8 H5 B9 t6 Q9 Z$ E( S* d" v% n
3. **重复处理**:1 c" U, N0 e2 b" O
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。
$ D1 L- N) m! G! n1 ]( g* {
4 U8 v' P, o$ r* ~* i# M3 D$ e5 g### 示例代码
  J- B* F3 n3 d! v0 W! f" p! N7 Q: _* J. J  c
```python% K6 v+ R$ k% n& w& C. J
import heapq, T" K9 m4 x, T& N# ]. I9 S

5 j0 U" k# ^5 F1 edef dijkstra(graph, start):6 l: W% r- M" X/ W* |$ W; l
    # 图的表示为字典,键为节点,值为邻接节点及其边权
+ k) a. ?9 J" W' ]4 p+ ~/ l' l    queue = []
. p2 Q% l3 C- n+ K    distances = {node: float('inf') for node in graph}
# U+ A& J, C. N5 S; E& ?% K    distances[start] = 0# h# p) \" X0 S; f/ V, [
    heapq.heappush(queue, (0, start))  # (距离, 节点)% ]7 R+ _+ S5 j% i" H5 v! w( `

6 v. v# O: s' Q0 l1 j8 N3 m/ E    while queue:. H% C4 o+ a3 I
        current_distance, current_node = heapq.heappop(queue)  Q0 n9 F5 R/ h# ?6 c
; H- j2 C$ _, g" h$ \7 S
        # 只处理当前节点的最短距离6 _: ?; z8 R* |% ~$ B
        if current_distance > distances[current_node]:
. T3 R& u8 c: F0 a; y            continue
/ s) I  c3 x0 Y) v3 H7 H  ]6 H% D; g& g
        for neighbor, weight in graph[current_node].items():
; \6 I+ w8 h& P" U/ a            distance = current_distance + weight' y/ p+ v( w5 y/ u! S/ P# ]
' I7 S7 i% u' y% d& [2 B5 [
            # 更新邻接节点的距离
( b* t8 T( E$ J- p6 |# w; l            if distance < distances[neighbor]:
8 u0 ~4 W$ o' {1 N" T, z) g                distances[neighbor] = distance
* L5 B9 \" ]' q7 K                heapq.heappush(queue, (distance, neighbor))8 A0 J2 U7 b7 l+ D1 N3 h

+ i' r# k5 N1 n9 x: b, q9 a    return distances* a- f# v% G8 L3 r) o; G
; t1 b' _7 W+ Q0 c8 B
# 示例图
0 B1 K4 h' d" @+ t! e4 X4 R. Cgraph = {
3 R7 v4 O& c3 _    'A': {'B': 1, 'C': 4},
, `% q1 G  l$ N- Y; I. ]7 }' O    'B': {'A': 1, 'C': 2, 'D': 5},
/ n  ^; B7 H2 l0 y  `* A1 m    'C': {'A': 4, 'B': 2, 'D': 1},& R' E; [3 ?" Q# O9 r
    'D': {'B': 5, 'C': 1},) ^" Y5 c. n  }- B" ~
}
7 D4 w5 ]1 v8 j
8 Z8 v4 W, _- `start_node = 'A'
* |. v( i$ U* Q0 Mshortest_paths = dijkstra(graph, start_node)
3 U$ Y# Q; m  c7 `- `4 Tprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
" G! {# @: H1 O* u' V```0 t" _  E9 V* S! {9 t

4 j) b. n$ r/ L8 J0 Q$ b## 2. Bellman-Ford 算法
3 {4 x' H6 k5 ^4 l- Q( a# j/ q. D: c- x: `* B- ]
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。8 \9 Y; c: u( Z" W' |( l
4 O1 z5 ?! D3 h; @8 N' X
### 原理步骤
0 n; \  l0 P/ o; R' K  `3 @" A: D4 W" {* B* k
1. **初始化**:- J9 e9 q& V8 i3 E7 {8 ^/ A
   - 设置源节点到自己的距离为0,其他节点为无穷大。0 Y* k/ z" W: k9 C5 C% P+ k/ @* a: e
) ]4 R$ g# {. f7 ?2 H
2. **松弛操作**:
4 y# O. H+ _0 ]! e  T1 t   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
' }* n4 o: d  r- u# ]* H3 f5 F: p8 I
3. **检查负权回路**:7 D0 q4 J) M5 V5 F8 Q% p# R' X, j0 w
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
8 q' q1 }8 s! u1 y7 R; X2 N" \9 S
### 示例代码
$ b0 y% O7 T9 Q( g5 N- K/ V) I
# i* E* m: S# I! ]5 L```python6 j( l/ G/ o4 ^+ _
def bellman_ford(graph, start):
. \0 {5 H2 _/ ?3 y! g0 ?9 M2 z4 O    # 初始化距离
/ X* M4 r* a  j' G# |3 q& W    distances = {node: float('inf') for node in graph}
7 ~! N/ u  f- Z/ k    distances[start] = 0
6 O: E" C. a! z1 F3 F% r% \6 M8 z2 s7 V
% l4 |7 z: A; x, k; B, k) j3 k    # 松弛操作8 b  z( D0 D  E/ R: k
    for _ in range(len(graph) - 1):
7 V7 U5 K0 R' b7 k0 v- M) G$ Y3 {: k        for u in graph:
+ R) c% ~" Y, Y  D4 ?            for v, weight in graph[u].items():
  A2 Z# ]; {% b( b  m4 p                if distances[u] + weight < distances[v]:- {( f' S! o& U5 n
                    distances[v] = distances[u] + weight
$ U8 b  o) J3 I# s- s( a+ r- ^: ^9 q1 S" l7 `
    # 检查负权回路( P/ `2 |) o( M. u. k
    for u in graph:: q. c' [/ \4 V
        for v, weight in graph[u].items():
2 s' M! A7 B  E7 b3 R            if distances[u] + weight < distances[v]:
+ T' S# {  O5 h1 a                raise ValueError("Graph contains a negative weight cycle")3 b1 Y4 v6 q: \+ Q1 @

+ N2 m( ]8 h) C" W0 ?    return distances2 l: Z" h; h: j  T9 @  j( m

5 Z% Z/ p' S3 L' c1 ?( ]# 示例图(带有负权边)
- n0 q7 X0 L" M& m# u% C% Tgraph_with_negative_weight = {! e# s' X% ]1 k) m
    'A': {'B': 1, 'C': 4},
: m6 Z2 j, r' ?9 a9 V    'B': {'C': -3, 'D': 2},
6 J& C7 ]  Y' q, p$ l9 h9 G% i    'C': {},
7 o, w2 E/ A7 u, g: l2 O/ J; @. J    'D': {'A': -1}
7 i& l6 ~7 D$ |1 R7 u; K}
# b2 H. P0 ~: @+ @( ?4 u2 z  ]7 y4 o
start_node = 'A'
* s2 B  v) a: u( {, Oshortest_paths = bellman_ford(graph_with_negative_weight, start_node)
/ P5 z+ l( W" e2 hprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}0 S" c6 {+ h/ R
```
7 w7 ~* \4 o) L* J% L- k/ \7 A7 a. ?& j: f0 [6 O
## 3. Floyd-Warshall 算法# H4 H9 q" y, B0 [' Z

7 x# Y6 J7 S) b- d( k( @! D; JFloyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。6 k6 e5 T) Y+ @! ]* G* H0 B

. m2 K2 _( i8 J' v3 v! q! j### 原理步骤
9 v( i5 ]' @% `4 |
, W8 y% y' |7 E1. **初始化**:' [, J4 O/ V$ ^+ Q+ B# R1 X$ |8 d
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。
2 D- r1 H2 j! F- w0 r8 J; t! V3 t1 ?5 ^- C' k
2. **更新路径**:
2 g1 }9 T: u& t( P( V9 n   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
( g5 A7 N+ y' ^0 }% s1 {3 H# J
& Q, B- r# a  G# k' p' Z7 @: @- B3. **输出结果**:
# y+ N' w+ f& |, S) ~   - 最终得到的矩阵即为每对节点之间的最短路径长度。
- E- U3 E, t8 S; N. p2 d( V2 r+ M
; J$ _5 [% w1 l1 f- U- k' e### 示例代码) d) g9 A5 Y3 u/ J9 P: n- R5 c* t
. e- g* H( a6 m" K, M
```python. b" Q- P# Y8 q1 {8 W  ]; y
def floyd_warshall(graph):
: ]/ L9 W7 _9 T1 T3 B8 N    # 初始化距离矩阵
3 h0 H/ O, i$ F& C2 O    nodes = list(graph.keys())
' f3 \8 I3 j0 [: k& G: ^    distances = {node: {n: float('inf') for n in nodes} for node in nodes}% D  q1 h) X* R0 L( |* Z* O

( K* \, ]. r1 U" \3 R/ N    for u in nodes:
" u- n. M! h: ~  i" @- p        distances[u][u] = 06 W3 A/ I. D5 ^/ K8 B* D$ X' f
        for v, weight in graph[u].items():
. L! s3 T! O6 R* Z            distances[u][v] = weight8 W2 A; h3 G( m: @- E0 V) m4 B

$ e! R% N6 }" y- K% I5 C( I& B    # 更新路径
% P; Y/ R! u1 n  w$ j    for k in nodes:
  b" _5 Y* L; ?* W& q        for i in nodes:
8 w: ?  M( D' O) Y  W            for j in nodes:
' C% V7 i' J3 H6 J2 R  q' `                if distances[i][j] > distances[i][k] + distances[k][j]:' r) e( g) B* ]3 W4 O! Q8 Q& ~
                    distances[i][j] = distances[i][k] + distances[k][j]
( O0 _! S0 ?# `6 \+ ?7 U* A3 J& u& z: J$ x( i7 g( a
    return distances; f$ I* R  r4 P! [. ]+ a+ y9 B% Q

( F+ m* ]; L. I( P# 示例图(可以含负权边)
( [5 ]) Z5 M7 {$ A, E8 ]graph_for_floyd = {
7 g) W5 Z+ N. U2 @2 m    'A': {'B': 3, 'C': 8, 'D': -4},0 A5 L1 M" g- o
    'B': {'C': 1, 'D': 7},8 L: y& B* ?. A+ q- ], R
    'C': {'B': 4},
. Q9 n. ?% d7 V0 k  Y  }* ~    'D': {'A': 2, 'C': -5}$ W0 E: [4 K0 N
}: S" {/ ?. P/ K/ w2 o
9 X8 m/ l! Z5 I; ~, D
shortest_paths_matrix = floyd_warshall(graph_for_floyd)
* I( w1 w( k' l1 ~! ~! a0 Sfor row in shortest_paths_matrix.items():
$ X* A# M' ?4 C  g; J. p" Y    print(row)
  B" l" q) O+ Q0 P- [```& Y) ~0 _, T" Y/ q

) ^1 K/ k1 y% g3 }4 r% u0 s( ?) @## 总结
! v# u  N! @% p1 @  u
2 s+ p7 V4 X' C) t7 q/ d- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
( c% D  h+ C: e/ w8 c  Q4 [( r+ V- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。1 k! G7 o1 x7 n! `
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。
. I: n/ n" {& s" [5 f1 S& e' l3 U5 t5 }0 `
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!' I. }4 s3 R6 l, c& Y" N' W; h

$ D3 N3 f4 N7 {2 F" l
6 Q# X& C0 J7 h# S: m- U1 m% ], Z3 y2 n* 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-6-10 23:36 , Processed in 0.477387 second(s), 55 queries .

回顶部