QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1198

主题

4

听众

2976

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |正序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
# W. D* z( R- Z( H2 g5 n5 I$ r% |3 ?6 E
## 1. Dijkstra 算法
1 r3 ?) Q  S& O7 \4 f0 }& I; Z! Z# p6 |! Q. B
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。) X+ Q7 d; A* ~

0 L: u, a+ K5 q  M" I2 L### 原理步骤
4 W% X* |3 _$ I- s, \6 z
: J# T: s$ W, R  H3 o1. **初始化**:
) r! O  Y) ?& B6 E% Q2 T/ P2 ?9 D   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。
4 s  p0 S* e/ y2 e$ I3 E% u   - 初始化一个空的优先队列,用于存储待处理的节点。6 E8 A3 g6 M( I
1 z3 d# f. h  W: z) u
2. **处理节点**:
( b. ]0 v/ L' l) Y   - 从优先队列中选取距离最小的节点作为当前节点。4 A! K" V5 u/ c& u! U* E
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。! H% U* u# {& G5 d! L: e
3 ~$ n0 N& k; e/ N7 B- O5 p/ }
3. **重复处理**:
0 M$ [) |/ T7 u6 m3 J0 I* A1 r   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。2 C; W: }: P4 P# C" T5 c

7 b+ l, }1 M2 h2 n) a3 R### 示例代码
8 [% ^& s$ V+ `2 L  j3 f3 _0 ?  q: j5 e7 V( T  r
```python. P4 ?8 f; V$ B: Y. y: G
import heapq2 W# x5 J* Y; _6 b& f

% g( Z8 W+ U8 k% rdef dijkstra(graph, start):
, S. M  m2 T& }, V    # 图的表示为字典,键为节点,值为邻接节点及其边权+ l9 u, t0 `5 q8 |& P
    queue = []) y" j% N7 C2 }8 @- }, r
    distances = {node: float('inf') for node in graph}
1 y$ b+ `1 B. ^/ ?6 z* ~  e    distances[start] = 0% U! D; |' E+ L: W7 L
    heapq.heappush(queue, (0, start))  # (距离, 节点)
# w6 N3 o7 O5 z8 m9 M, ?+ A7 ?: c- h. w$ F
    while queue:! L3 Z5 f. X) D, X
        current_distance, current_node = heapq.heappop(queue)
8 b; x+ \6 H3 P7 H; Z' R" ~- ?: m3 I6 n: ?! {
        # 只处理当前节点的最短距离6 o) [* M) I$ [! }5 A9 ]
        if current_distance > distances[current_node]:! ]0 {1 Y% h6 T  X. R, _8 H# A1 g! n
            continue
- h6 ]; h, }) Z! P( s5 r! \& s% q+ T
' R# z# _! @& a8 m5 a3 O        for neighbor, weight in graph[current_node].items():
3 ^: [7 ?$ b) ~1 o) H8 V            distance = current_distance + weight
: m! N' A% ^3 J
9 S6 c) f! B6 m+ G" s% f            # 更新邻接节点的距离
/ T( P* Y3 l: f; _            if distance < distances[neighbor]:( L5 x' y1 b; W! n6 \5 ]: F
                distances[neighbor] = distance
$ ~4 v- r+ k: C  w! K: _- t                heapq.heappush(queue, (distance, neighbor))
  w) ]1 Q3 Q4 Y, h9 p/ o2 [
/ x4 n: ?1 d1 _2 G; P* O    return distances  g' K& A' ^1 q4 Z( g

" H, }: g4 ]$ h" e0 u2 z# 示例图9 I7 K$ a9 V) S+ J% N9 @
graph = {
8 R, r0 s( z- @* D    'A': {'B': 1, 'C': 4},
+ c! |1 k& ]7 H; V8 S    'B': {'A': 1, 'C': 2, 'D': 5},' E. M, `* G1 U; y* E6 V9 L
    'C': {'A': 4, 'B': 2, 'D': 1},
) j6 }2 x: U0 V% Z' \    'D': {'B': 5, 'C': 1},
4 |. R5 u" Y/ R" Y  g0 [}
5 d2 A, c9 i3 u  X- e. {: g1 `& J' M* M' Q  }
start_node = 'A'
) Q- u  w* q: o. v- M- Rshortest_paths = dijkstra(graph, start_node)$ Z5 Z( d+ Q5 C9 L; o# B! p
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
( R) f& n: K7 W  B( W```  ^$ p8 K' L; q4 F! S' B

; _5 ]' I4 m, |0 d* f## 2. Bellman-Ford 算法$ q9 Q- m  ?1 I- G% {: w# Q. Y  J0 I

6 J: Y& |+ G0 J' iBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。6 B  |8 _3 y; l0 w7 P& _

5 X7 L5 X' X% Y### 原理步骤
1 q7 h, H# L% k2 t( e/ o% B
" E9 P+ j* g7 l6 a: v! P1. **初始化**:
- |+ P0 _& }! |: W! j) f# t8 t5 n; n   - 设置源节点到自己的距离为0,其他节点为无穷大。( Y& r4 U' R, }+ D
3 ]! C! B+ l+ t9 V" b4 m
2. **松弛操作**:
: k, D) Y8 [6 K/ g   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。5 L+ `1 h5 Q9 V% T2 B
$ ]" A. e( _: }9 i7 g
3. **检查负权回路**:
& r4 J: r0 H8 ]5 l8 f- H  Z   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。3 w+ @7 F1 q- ?  V2 e5 {  M- x
( ^' G4 e5 z+ Y# G8 ?3 I3 V6 o
### 示例代码% m/ f- G' h$ A% I

0 l+ R% c0 g9 D2 }1 ^) }% K```python
# q. H) D  R1 U9 l1 q  ndef bellman_ford(graph, start):
2 k9 m6 |& f4 ?4 q' D9 u    # 初始化距离
  ]: C/ u" p( `) n, C% X    distances = {node: float('inf') for node in graph}& q% ^( d; F. q/ ?7 q8 o
    distances[start] = 01 s2 {+ |& g/ L* H! E! c2 A/ g" D2 }0 y
9 q! j6 G! i. j" f& b
    # 松弛操作
8 G1 E1 b* m* K: e    for _ in range(len(graph) - 1):: C9 n- y; v- w. B0 [% `
        for u in graph:
! O  [1 E6 i: f4 \# q& \+ M1 H            for v, weight in graph[u].items():& i' }0 V1 k0 p  v7 ~% J
                if distances[u] + weight < distances[v]:
+ x+ l; G9 i" h5 u5 e* q# \                    distances[v] = distances[u] + weight6 e8 M: j2 ~, \9 T) W# J

% k, d; i6 w7 N6 u* {$ w5 Q7 ?8 q! _    # 检查负权回路3 }0 F6 r4 f! R; w* ]: q6 [8 T
    for u in graph:# f8 A+ U3 t, ?! g) b; F7 k1 O: H
        for v, weight in graph[u].items():
& H1 H' \0 I5 h; i5 d( H7 C0 e            if distances[u] + weight < distances[v]:: s( d8 e% w! _) c# N' \+ O
                raise ValueError("Graph contains a negative weight cycle")
. F0 I+ m+ l  T' G/ V) j4 a2 \: F* }- _) m* ^3 r; B
    return distances
* R7 S) q8 @0 x( I$ E, z
- q5 n. D$ M) Z6 }' ?0 W# 示例图(带有负权边)
) u' ]" R$ N0 }. ^( c! z; ~graph_with_negative_weight = {3 x6 y+ D! R8 R6 Q% }% c/ d: ?
    'A': {'B': 1, 'C': 4},& X3 D5 V  w# S& _% u1 D7 v1 I* e
    'B': {'C': -3, 'D': 2},; _0 ?! V  S6 W+ B, }
    'C': {},- a5 E( L6 T0 U2 w7 ?% f
    'D': {'A': -1}" e$ Y3 x! f. V; N) D
}
% j) J+ w7 `% x  f/ y/ q3 J+ P0 m0 O( Z4 }+ u0 p* W) B1 K
start_node = 'A'
/ S: P6 _/ R6 Nshortest_paths = bellman_ford(graph_with_negative_weight, start_node)8 W- |' S- m* }, I
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
" Z. s0 Y2 E+ i8 D1 ^```, Z! X- K9 |# P- M
. c. H; J( f# N* K. p/ _
## 3. Floyd-Warshall 算法( N3 E0 q6 x# X- T, X
6 a; |' |% y9 v1 V
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。8 p7 \4 k3 l4 o; @2 ^3 L1 i

1 P! z, @9 c$ e3 J2 ?### 原理步骤9 P  _* H# B" }# s4 M! X

# G( b: {4 Q; _9 p- P1. **初始化**:( ~' E' G/ F" p9 G
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。
+ i2 ^. Q' R1 o* r9 n' H, k+ |; c+ C
2. **更新路径**:4 P9 k4 V5 C: P. M6 \
   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
% B1 h, Q0 @4 U! ^7 K
0 `1 C, r; \: V* x6 |5 b3. **输出结果**:
+ F( d- H8 h8 Q0 H7 E- s   - 最终得到的矩阵即为每对节点之间的最短路径长度。
0 |! W! S0 _. i# f& ~7 j
# w5 s8 p) V1 U# z0 j% c### 示例代码/ m# g! N+ O6 f- @# E
7 F1 R. r" _% i% ]' |/ W
```python5 ]  Q" E, A) |
def floyd_warshall(graph):
% _5 @/ A" V: I    # 初始化距离矩阵2 _( B& S0 w9 I! c: b
    nodes = list(graph.keys())
& y7 E% ]( g0 A/ I8 \% H, {" y    distances = {node: {n: float('inf') for n in nodes} for node in nodes}
# H6 k& i! A- T) B! x* n9 w3 K% T9 @5 x% J/ C+ b
    for u in nodes:6 W2 S0 g- C! R8 H, D
        distances[u][u] = 0
% F: j8 H. m# t, P/ @0 a        for v, weight in graph[u].items():
& d, W2 X8 o4 v            distances[u][v] = weight, \& }( k: S1 g* b; O. S: P, U, U

, q* N& f: L& S5 ]- N2 U0 W& M    # 更新路径
6 N" y( E( r/ R: o! e    for k in nodes:
: c  L' l4 y' v6 t        for i in nodes:# b$ M/ y9 B. Q2 c
            for j in nodes:
: T7 X6 N! F6 G8 o8 f$ f                if distances[i][j] > distances[i][k] + distances[k][j]:  L  D# Z; U7 z. J6 L) V
                    distances[i][j] = distances[i][k] + distances[k][j]
/ V# M' a7 K2 M$ z! w5 ], {' l0 t3 ~1 X0 L( @- A; b
    return distances
+ E* D* v8 y5 u* C- N9 t* f3 k4 x
# 示例图(可以含负权边)' i& y2 E* v$ J4 n0 g
graph_for_floyd = {
, z3 c. g& m- L7 F' @    'A': {'B': 3, 'C': 8, 'D': -4},
# g. U! B" ^. o1 r$ n    'B': {'C': 1, 'D': 7},/ A9 W4 f+ b, o4 q, [/ x7 s8 K
    'C': {'B': 4},
7 F9 `7 d# `, |/ s. P    'D': {'A': 2, 'C': -5}
5 q# O9 W3 q+ S: a  Q1 d9 C( Z}8 V0 J& W+ O! e; S$ \

2 w- D( Y) Y+ ^7 g: l7 z! l$ Qshortest_paths_matrix = floyd_warshall(graph_for_floyd)
  K. y) n9 D+ @  g) {0 ]for row in shortest_paths_matrix.items():3 v& ^; [3 |& e; P' j
    print(row)6 O* r* I, u  F; j8 t6 ^9 [! c
```
7 \( _8 J3 b6 p6 w- P2 e; t. F( E
; a8 c: \4 j2 _" b/ |## 总结
' z; v2 L6 s! v3 x: j# l& o9 z0 O
* {. O. U4 X2 n' X- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。% X( V* u7 D/ |2 y* X
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
) s* u4 W; C+ Z, d3 i, [- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。7 F. m  L' d) q5 ?

2 p0 o; ?* E! \6 }不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!
: v; ?- s1 i( y' H- Q+ o" P) y- t4 \1 n) e! B

% d: @- b7 B8 |6 e6 }7 ~1 @8 Z* Q# q4 v& ~, N7 ?, O0 [/ W2 _

最短路径算法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-9-13 19:46 , Processed in 0.392065 second(s), 55 queries .

回顶部