QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1186

主题

4

听众

2923

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
- \, W$ W* G, x& _' h# O* C, I8 w& `9 U6 |* f0 ?( T2 d
## 1. Dijkstra 算法
- F$ k2 M& q' T. t
, O( Q. x. m: JDijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。6 a# x! F7 c0 o+ Z3 w0 H/ B' [/ {* Z
) Q& w; x! v6 L1 F+ a4 L
### 原理步骤9 n! R2 d1 F6 L* k4 L8 _
1 j6 _8 }, }# C6 f5 _4 _6 }8 S
1. **初始化**:
) t4 E1 U& ]4 c* q   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。
8 \$ G- _4 D- }% S1 h   - 初始化一个空的优先队列,用于存储待处理的节点。
* h% N$ D0 {" j. r$ u
' s7 h, z' q0 `2. **处理节点**:
" j: U1 W( B( }* ~( U   - 从优先队列中选取距离最小的节点作为当前节点。
, S  L- K+ g& \1 w6 o% T8 J   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。5 B+ ~8 V, L7 ~* u

0 Y3 Z# V- n: e( G2 F9 u3. **重复处理**:
; q. Z: g7 O  |. }& C- ]   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。
$ \9 T0 P" s- v; {4 F2 G9 Q( _' p- |: A
### 示例代码! z' i+ Z. a$ x0 l8 A) I

4 ~0 m9 V( H. F( E```python
" Q# ^  u. [; n$ K4 @* j! Iimport heapq/ A! ~, T/ g8 N, J, A* s/ X

& G  y2 w+ v5 \( W) Sdef dijkstra(graph, start):3 C; C9 A& S. z+ @; B
    # 图的表示为字典,键为节点,值为邻接节点及其边权
7 R: G/ j7 u5 w% d9 t: t    queue = []& j- R* K+ ^: |) y
    distances = {node: float('inf') for node in graph}
- o. E% t4 m* g* ^9 z  S    distances[start] = 0
" s9 ]+ ]) W% W9 w% X9 M5 T    heapq.heappush(queue, (0, start))  # (距离, 节点)
. L% [. ^1 G0 p: b$ n7 _: c1 b
3 K6 T/ `+ u9 Y7 l" J4 i    while queue:5 d. W2 B4 t5 R6 s, e6 a2 J
        current_distance, current_node = heapq.heappop(queue)6 h8 m1 O" \% L* y) r' u5 P  Y

; |( v3 _& N" U( e. m        # 只处理当前节点的最短距离
2 \/ X! W) v/ E7 M3 r        if current_distance > distances[current_node]:6 u" G8 d/ E$ w. v5 A# X
            continue4 ^$ \* [/ v1 S0 |2 C& {3 m: r7 R* K
/ u5 V# l% z  y0 ?, y: l
        for neighbor, weight in graph[current_node].items():  w* u% u  W' y; K7 T9 ^- B' E
            distance = current_distance + weight; A% n; q  Z+ Z- ~0 [6 ?8 S

$ N2 F7 x% h6 F" u* q- h* y            # 更新邻接节点的距离
0 q3 h$ F' [! d2 a/ m1 G" t( @; }4 T            if distance < distances[neighbor]:
: t! P0 n8 [5 w  ]/ @                distances[neighbor] = distance
3 l" F0 V" L" V+ f! P4 {6 z6 o                heapq.heappush(queue, (distance, neighbor))
( \4 }* O: T' u5 c, `! [2 w5 e/ W4 d/ H. M  r5 A8 y: I  t
    return distances9 k$ y/ E% W8 S5 W& q4 \

( k( M, x* Y# ~- W- F# 示例图
/ w, h- `* V% V, T# W+ pgraph = {+ R3 a1 r; Z% _- w
    'A': {'B': 1, 'C': 4},1 z: B0 x; l( o# Q& T4 J
    'B': {'A': 1, 'C': 2, 'D': 5},/ }  {" T1 `0 @% e, f$ ~
    'C': {'A': 4, 'B': 2, 'D': 1},- I8 g) K( B  R; T/ I
    'D': {'B': 5, 'C': 1}," m# ~9 D6 m/ [0 Z2 a; l# d
}5 o* n% V8 q; N2 ?: y
; ]) l- B. R8 ~
start_node = 'A'
, J5 L' l& Q( y* d4 ^shortest_paths = dijkstra(graph, start_node)
  `; G% _; R: J/ o' d- e8 bprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
# s. N. l' W8 o' i( h$ ?! E```
& ?+ v6 X+ K# o4 @  N4 B% }! m- w  W# T1 p, t
## 2. Bellman-Ford 算法
" V. `5 D. {0 O8 I' i& g" k% V0 M& G
$ R6 d6 b& k" q$ d; hBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
0 r( M: r& e' o9 w. U' ^0 f: }  f- F1 G1 f& V) t+ m, z
### 原理步骤. ~" k; `, ?4 D

3 {! {, p3 Q# a: b$ f! x1. **初始化**:8 h: f( q8 B6 `, f" s: v0 U
   - 设置源节点到自己的距离为0,其他节点为无穷大。
2 X# ^9 n# f7 b  w8 V$ l  T0 {) Z& a
. |" d2 T1 h# l# p5 V. d2. **松弛操作**:! ~* F  z( H9 T" z
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
4 r' z% D& S" L/ C  N9 B
8 p# e, o+ C* u1 J6 a! p1 f7 h3. **检查负权回路**:
* E* u0 r1 z0 Q1 v" I   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
$ a# x- }3 Z3 S$ O% ~/ i! d
6 ^' Z+ k- o- L8 N% G* [9 a  A- e### 示例代码9 C! |$ b3 d4 x7 J: \9 [9 O
* E$ G  x4 l  R, y0 R: s1 x
```python
2 ?: L# r: a& m" mdef bellman_ford(graph, start):/ x8 o! l1 [6 C
    # 初始化距离9 W( P2 h. ~4 A* q5 o  q
    distances = {node: float('inf') for node in graph}
. q1 [2 S/ w9 h2 n* {5 P# L" X    distances[start] = 0
) y9 E0 m/ ]! ^
  F# F# r( }* w9 U7 x    # 松弛操作
& s# {0 K4 |2 z" D    for _ in range(len(graph) - 1):( J% ?1 H. R  W
        for u in graph:& t6 R+ \  F; q: W
            for v, weight in graph[u].items():
; m% e- s6 O+ v6 Z- Y                if distances[u] + weight < distances[v]:' m$ O1 B  ^& k0 k8 G
                    distances[v] = distances[u] + weight* r& M1 y( @/ W

) M0 i3 `% F/ p    # 检查负权回路
9 j+ i1 M" N( d% X; f0 s7 I7 Y    for u in graph:/ o, W/ K6 \3 e
        for v, weight in graph[u].items():( s( |; Y1 F- T6 ~! T( G+ P$ W
            if distances[u] + weight < distances[v]:
& F2 O3 @9 `" S* c: w" `) y( [: ^                raise ValueError("Graph contains a negative weight cycle")1 A0 |( G1 _/ \- o  E+ i6 D

, z5 ~! Z) K( S, W    return distances
( g7 z- L3 u, f. R; f( l" g3 ^9 k% L' B5 j* j
# 示例图(带有负权边)" x7 ~$ v& [3 P
graph_with_negative_weight = {& K, c( j5 x$ T0 o
    'A': {'B': 1, 'C': 4},
: [' `% u$ P- l5 a0 f' V2 T    'B': {'C': -3, 'D': 2},
9 r/ `& C3 j. I+ k) P" d# v    'C': {},
: h3 N: ^1 d/ }7 [1 u( Q" h, m    'D': {'A': -1}! K8 u  \0 C8 z3 G* e% `" w
}, Q  p! x  U: K

# h% x7 w! O1 t' g% I6 p4 R& c' xstart_node = 'A'
) S8 P: ~8 n2 Y( G. V. Rshortest_paths = bellman_ford(graph_with_negative_weight, start_node)* k6 k+ z& k) ^$ A( T! f
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
9 f& }8 v; L/ a```
! s+ C4 x6 u6 @: U; i
) B8 z4 ]* x$ P' c7 y## 3. Floyd-Warshall 算法
* t! C5 L; l  h( L5 U$ Y5 G& g% @: d( @2 h' T$ k
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
8 L* ?$ K2 q% U& ]
: P6 p( G; E+ C# t) U### 原理步骤
; b# M' L9 Q# Y+ @
( f" a5 y. s4 n! h4 K4 p1. **初始化**:8 G" w0 S  V; s; C( M, n
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。/ I* N/ |" D& @& a- g

) I- s  o5 \7 T3 j+ I2. **更新路径**:" o5 u+ E4 z1 j6 f
   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。5 q; h( F) x0 Q

; m5 {  T$ i  C! Z: T3. **输出结果**:
" a) u7 w: _* n$ a1 x   - 最终得到的矩阵即为每对节点之间的最短路径长度。/ T6 \* `( m5 h$ A6 ~  d
7 c) f: z& `4 D8 l: G1 E% U. d
### 示例代码
6 L1 I5 J' g) s; p
' D) ?: {- N, T7 T9 k```python
9 r# E, P" |' e3 t. Rdef floyd_warshall(graph):/ k4 }1 n: L9 X1 }1 u' f3 c' A
    # 初始化距离矩阵
, r! o, C* U# P8 S# r7 l- s    nodes = list(graph.keys())& _; T" \0 f) k. B- |, o
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}3 I2 u! y' b) g$ @  w
) X' P) l. l& U" O4 B
    for u in nodes:
/ q. b, X8 F% C' S; i# W6 H) g        distances[u][u] = 0
3 f2 `+ G+ R! W. g- v, ~        for v, weight in graph[u].items():
/ v" A: F# f, Y. F& I% V: s            distances[u][v] = weight
' \; u  p. ~& v* b+ v! Z: u! ]6 C1 w/ e0 R6 V
    # 更新路径9 {, [& \  b' O* @- O( \( k0 N% i# m/ B
    for k in nodes:
5 G# i- w  O2 e! D4 X' Q        for i in nodes:
8 R) w: K6 f1 o& Y% |/ _( i7 i            for j in nodes:+ c# B6 R/ D5 w5 O9 B6 W: W
                if distances[i][j] > distances[i][k] + distances[k][j]:
$ v  {2 |9 |- j2 K  u/ k                    distances[i][j] = distances[i][k] + distances[k][j]
* E0 s2 {# l% u% l3 w+ G, m5 j" c. V5 G8 C) D
    return distances& @* {( N4 `0 e1 E8 P' ^

2 Y. t* L6 W- q% |4 D# E4 ~# 示例图(可以含负权边)1 `: ?" H# N. \  `- ^2 c" ]6 D5 d
graph_for_floyd = {
5 U" E6 U0 v' D; }    'A': {'B': 3, 'C': 8, 'D': -4},
: q# n3 Z% Q+ e  V2 R    'B': {'C': 1, 'D': 7},
8 m, F+ _* Q: e% n$ @- W    'C': {'B': 4},
" p% y: N+ c6 O, e& b' r5 y    'D': {'A': 2, 'C': -5}- T& W6 p- [) y5 H  w: p9 [
}
* a' c9 x. a" n- d8 M! e
1 r' _) `- w0 j- m* Y5 Cshortest_paths_matrix = floyd_warshall(graph_for_floyd)
6 Y- j+ j- d. ]+ Lfor row in shortest_paths_matrix.items():
' n* D7 C' E) D! C5 ~# r, k7 _    print(row)
1 }% o6 n7 n$ H; o. V```
, ~; ]! U! K/ k( D+ L5 _/ u' u3 t/ S1 M2 Q5 l( \0 R
## 总结
" i9 i. p% u' r# h# q- ~
- q& n2 Y* p; l: b, ]* S* ^- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。# {8 l% c7 i) o, P' B) J, T
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
& w4 b' E4 R  e- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。$ _- g! c3 h% [0 w7 x

2 E4 j: [) J6 k1 o: I不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!2 Z! m" s, G' N! s9 ~" C" _) r
" L/ y- J# J1 ]
7 J5 E3 R; y' E9 x( ]

% }  K8 a, i$ J- |) g

最短路径算法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-4-23 17:56 , Processed in 0.570276 second(s), 54 queries .

回顶部