QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1175

主题

4

听众

2866

积分

该用户从未签到

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

0 Y9 ^1 D: s. o9 Z## 1. Dijkstra 算法$ S, E7 Y/ I1 g# r
4 J6 G+ L( M9 ?% h6 w0 _9 V
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。
* E$ {' K5 E+ A7 C
/ F) i- c7 x  Q  m/ x### 原理步骤- U) e2 m, J5 U0 F7 h" g
1 [1 Y4 F9 ?9 z* A+ c* U
1. **初始化**:
  K* M$ s8 ^" u/ x' k  S   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。
8 n) L) u* }' ]( ^" j, }% N   - 初始化一个空的优先队列,用于存储待处理的节点。7 i+ O4 l) @, ]" K! u
. U# ~% Y0 d8 _$ x2 g
2. **处理节点**:- k4 x  {! T7 w. R0 Q, P& g# M1 U
   - 从优先队列中选取距离最小的节点作为当前节点。9 K# E0 }# |4 B8 X1 d9 `. n$ z
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
2 l( |% _+ ]" n& j
/ F2 P5 U! r* Q! F) h* r2 d; y# _3. **重复处理**:
5 h" h+ V" C% D/ e  }: U! a   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。
/ G9 G' P4 }4 [0 N, ?% [5 B  M3 Z; J5 s: ~5 n$ A! g# ]
### 示例代码
1 r" ~$ B$ j3 U4 E4 w
' F) k% {0 ^6 L# }( `1 W```python% D9 V# G' p9 l: C
import heapq5 z8 K1 K+ o) ~) Y2 ?
$ A( S3 Y( H0 {% J7 z
def dijkstra(graph, start):* ]. T1 U; v6 e0 g
    # 图的表示为字典,键为节点,值为邻接节点及其边权4 H- q* m) u9 f: o
    queue = []: S; G; m( K- r
    distances = {node: float('inf') for node in graph}- d+ g3 H3 ^! w$ A" `9 V! U- O
    distances[start] = 0
* W* p* ]" {( a+ d; S    heapq.heappush(queue, (0, start))  # (距离, 节点)7 @  A2 o9 D& `' H  [7 u" r

  l  P) G& R* U    while queue:
8 R0 ^  f9 S6 A: F2 k3 e' B2 Z" a        current_distance, current_node = heapq.heappop(queue)
( J5 W2 h4 U: f$ U; V7 m7 B
' n  g9 B# d1 a) o& T        # 只处理当前节点的最短距离
# ~6 z4 }9 |- c0 o# f8 @        if current_distance > distances[current_node]:$ G6 I# I8 @2 m3 W, A7 _. r
            continue  c: K- S/ p4 }" N

$ u' Y& s% d& I* q+ z        for neighbor, weight in graph[current_node].items():
1 e* k( N+ p! I! i+ t, t            distance = current_distance + weight1 I: k( l/ L4 A6 n4 h1 k5 k" k+ P0 E
$ O0 m5 S8 @# s$ }9 G. |8 }" }3 F
            # 更新邻接节点的距离
7 a: t% }0 _! t% t$ d            if distance < distances[neighbor]:
: L+ I* _0 Y4 W& ?* F2 k" r                distances[neighbor] = distance
9 C) P* ]' a! ?2 O                heapq.heappush(queue, (distance, neighbor))1 O- H2 M2 M# o* ~7 b5 n
  e8 h. F. e; v3 B" a( p6 m6 t
    return distances
" F' N! E- X8 A$ _/ a$ E/ K3 y$ s+ N
2 [' R, C# ]" y4 m% o" s# 示例图: i' X5 T: W) ?7 M0 S
graph = {/ h0 Z4 Q0 C8 m' [
    'A': {'B': 1, 'C': 4},. D' }  c! n) S8 G/ A1 c
    'B': {'A': 1, 'C': 2, 'D': 5},
( H# n, O5 C) V* b0 T4 Z# q    'C': {'A': 4, 'B': 2, 'D': 1},
4 N4 y! r  f& {5 K    'D': {'B': 5, 'C': 1},6 q* l0 C5 u9 |/ ]) Z
}
  f* k, o3 o8 W+ I# s3 {
! k/ @6 b; E$ r! O; vstart_node = 'A'+ U% C8 t" z$ P0 r
shortest_paths = dijkstra(graph, start_node)
/ f8 G! f% I2 t  E4 {print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}. ?2 B' y; o# H: f  O
```+ s" w! y% P3 p! A$ x: r
2 t  }! F8 h; O$ l) N
## 2. Bellman-Ford 算法3 R2 V1 d2 z( k

. ^6 o8 x4 X8 o; i: E+ e% UBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。& u! q  L" Q# o

% E6 b8 n6 @3 V6 z3 G( Z& h### 原理步骤
2 X) u4 T7 ?! n; W* a+ c1 U+ B- ^
2 a+ b- @; y7 J% n2 D, G% g' U; E1. **初始化**:
! S1 ]0 N) R3 k9 P   - 设置源节点到自己的距离为0,其他节点为无穷大。
3 i" ]& J8 p( f) Z- {
  K! t) d1 S* o0 x1 {2. **松弛操作**:! W  \) }3 p$ P9 N. y/ t) Z- J
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
% ]0 h: S$ L1 A" I4 K, q, x5 U5 d2 \$ W# i% W( c6 ~* n- p
3. **检查负权回路**:4 W( y+ ?8 V9 A, _5 v/ ~
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
$ ?7 ^8 _( P: v! {5 x% S) G4 ^! E8 j: i0 \) F1 Y2 D3 g
### 示例代码
& t- g: m% N% A9 X: b* e; G% l" V; }/ @8 E
```python  m7 H8 A) W' N4 v0 _  s
def bellman_ford(graph, start):
% s% m6 u" q6 B# Z$ M    # 初始化距离* E9 U+ E6 w3 B* Q
    distances = {node: float('inf') for node in graph}( O& _5 @: L9 B6 q& c
    distances[start] = 09 B; f& Z: P3 ^

1 u* W3 J+ A$ T, K: L6 e3 ~( r    # 松弛操作
% O# R3 ~2 g4 @; h    for _ in range(len(graph) - 1):0 j2 M+ Q) ^: V5 N( D8 Z3 w
        for u in graph:
% b% u6 E% n) K( P1 d/ j6 M1 ^7 i2 g  N            for v, weight in graph[u].items():
* b" m2 Z: x9 Q/ m% W: Z: h9 Q8 r                if distances[u] + weight < distances[v]:- f& e9 l- ?& y
                    distances[v] = distances[u] + weight
$ P" O3 z2 s9 t9 H: n2 j1 S4 o# x/ K0 T, r% s4 `  q" R$ j
    # 检查负权回路
8 y$ Y5 g4 K5 D! C; s! u6 K    for u in graph:) V& K2 ?  @; X$ [( _1 z
        for v, weight in graph[u].items():" E5 U9 r0 y! ~! \& ^% K! V* a
            if distances[u] + weight < distances[v]:
: ?( E( V" G" w                raise ValueError("Graph contains a negative weight cycle")4 Y" |5 z8 p- g: y: ?
, P# {' x" W  I1 |# A/ v
    return distances
$ v  G# b) J5 V% |+ a4 F1 s) @; k; s% x
# 示例图(带有负权边)
" G! N- D/ X% S; ?3 Egraph_with_negative_weight = {, c# Z; W+ j( R3 \8 g
    'A': {'B': 1, 'C': 4},
/ Z, T+ L# ]% m9 R( Y* v    'B': {'C': -3, 'D': 2},
  l: K1 r5 F" ]! Q5 P4 B    'C': {},
* W. E" {) T9 \9 K' W, [, @0 p4 u    'D': {'A': -1}. M" n/ Z: E7 B  u; O
}
  H7 y' }# t, `- l" o) I' `& }7 u; a: v3 A: C; F+ K7 T
start_node = 'A'
' d: P# h7 K0 f9 B9 nshortest_paths = bellman_ford(graph_with_negative_weight, start_node)& M+ j; o- V, ^: r; ^9 q1 D( @8 Z
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}6 e+ l' n+ T3 M; G5 y9 q; Y
```) d, R! x% O  y' |" M7 {, O9 O
5 ?  A8 P5 S( b
## 3. Floyd-Warshall 算法
5 O+ V% i  E' ?, i0 H0 ^+ T) n9 O: [" z4 o
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。: B3 A5 v6 s% v( B. y
, O3 T! z' ~, Y
### 原理步骤( q; }1 E  m+ G( {. H* k* f% R* S

, A, H0 H* E& {4 S+ k& c( Z1. **初始化**:# p* S6 R! M+ T) x; j( Q2 G
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。
- p7 h# _5 I6 w8 }% \! R$ k+ H- [6 y
2. **更新路径**:
: Y2 J% Y5 N. D4 }' u   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
' ?4 Q3 ^* T' e% F* X8 T8 R
# x0 [  ~0 g- W/ F2 Y9 ]3. **输出结果**:0 h7 R" k/ p" M5 a  \0 b9 T+ @
   - 最终得到的矩阵即为每对节点之间的最短路径长度。7 R+ v$ h* S8 G7 x4 v* ^

0 G9 k3 }/ `, m, U, @; f9 W6 x" j### 示例代码
5 X- e% q) W# t0 c
( `1 v/ p# z- @9 y( ]: T```python% C3 h$ M4 q. I8 W
def floyd_warshall(graph):7 i: ]8 r6 K  r  ^+ [- c* N
    # 初始化距离矩阵: C+ k0 e. ~; ~( Y
    nodes = list(graph.keys())
9 J% f7 m- S  m- Q1 ?    distances = {node: {n: float('inf') for n in nodes} for node in nodes}/ z! h! R9 c; }! F

9 k# d9 x& r1 ?4 S; R( t' c    for u in nodes:
* K9 k) Y- ?: n: P' `3 ~/ l        distances[u][u] = 0/ S+ W6 c" ~) z' h& [  I( z7 E
        for v, weight in graph[u].items():
9 L# ^$ S1 P. b8 `. d. C            distances[u][v] = weight
( W2 _4 S9 d5 Q9 Z
3 b; f3 R, A1 j) p" r1 l    # 更新路径4 ?  V# u0 z! S1 L7 o2 M
    for k in nodes:( o* P9 S( `$ G* z
        for i in nodes:
3 N5 S' Q, @$ N            for j in nodes:6 y9 Y7 \' w& D0 b
                if distances[i][j] > distances[i][k] + distances[k][j]:
% I* C# A4 s6 {' g- v, o1 |& ]. p6 e                    distances[i][j] = distances[i][k] + distances[k][j]
: E& q" Z( H0 a9 y
7 i) S" y# E& }    return distances
; w0 z2 f+ j8 d2 I$ \: I# i7 K0 y! R+ o1 `$ n
# 示例图(可以含负权边). `, I1 y& r; D. q
graph_for_floyd = {
$ @/ b, L4 J. j    'A': {'B': 3, 'C': 8, 'D': -4},
' d& a5 H( ^2 l4 P8 ^& h    'B': {'C': 1, 'D': 7},2 |3 f+ X2 l2 D* O4 y
    'C': {'B': 4},6 B& N* ~7 g8 r
    'D': {'A': 2, 'C': -5}) x# \$ E% \! \& k3 A% i( r3 v
}- k4 o( x' {9 ]5 s! }% U

9 e* C" S( V8 M- eshortest_paths_matrix = floyd_warshall(graph_for_floyd). ]( m3 c% v8 C6 {, d
for row in shortest_paths_matrix.items():" B1 ]- d3 ?- r" N4 x" \# {. C
    print(row)2 r' ~0 ]( ?! l) z# Y( g. z% f
```
! \' ~* u. D, u. ?, L
3 c3 s6 C: O0 {2 L* k6 x/ g## 总结" o7 U& s) f& N
; k: N/ w* U* R0 z% ]/ G, ~; c
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。& J7 p3 H1 V2 S& A- b
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
" E7 D5 ]3 o0 K. t  J/ ~( M- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。' M! R$ t  ~! O2 i2 b

; m' s5 z, I9 }4 q- e" Q9 j不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!  g) y* D2 J) @  Q! V: V
) S* {1 t0 S: R5 j# g6 E

4 D* X. c! K! X3 {1 n% @; j
' u# ~9 M' K) |/ b- L+ R1 H' H1 ^

最短路径算法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-8-16 04:00 , Processed in 0.334267 second(s), 54 queries .

回顶部