QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1189

主题

4

听众

2934

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
$ ~: w6 m' X$ @2 Q( X% F
+ x2 L& X* t0 l3 v; M# Z$ Z## 1. Dijkstra 算法' k5 ^8 f) G. T$ c$ q8 w$ F
4 b6 |! C! C" x/ n# o) N( S/ u+ @
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。
4 z$ R7 k) e; `7 z) d6 ^1 T8 z- ?3 i8 H- W: `* J9 O' Q1 |* Q
### 原理步骤/ _* Y8 o' @5 \
7 ^, }* E1 |1 u9 k7 @4 L" y
1. **初始化**:
% N2 C4 z6 v) Q1 X/ U+ a   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。. ~! c6 F0 i; n0 ~
   - 初始化一个空的优先队列,用于存储待处理的节点。
! b1 f2 o8 N/ a% i; D+ O6 E5 D" }& K, z/ x2 R9 U; j) p4 U
2. **处理节点**:
" t; S% `. g- z+ e& p4 w   - 从优先队列中选取距离最小的节点作为当前节点。- [) s% e0 O3 n" M8 `8 [
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
! n$ W& l' i, f
, c- C- t! M/ R3. **重复处理**:, V: C' ^0 M0 L0 M
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。& @( h0 Z1 K4 ]) M$ [& ]" q
$ p$ }* R% o% s+ Y4 Y
### 示例代码
4 p. _' |! v+ Y' Z, A
. F4 L$ U$ }# C0 n, T' T  O```python
; T! r7 L0 ^7 @' b( Gimport heapq
5 [( c0 A; S! ]' t2 \1 A% f
3 `1 ~9 |7 o5 |  `; d. Y6 qdef dijkstra(graph, start):
6 }  W4 y& _% h: |- n    # 图的表示为字典,键为节点,值为邻接节点及其边权/ }6 i( w' X, A/ n( f
    queue = []
) i: o2 D( [5 v8 ~; r; E6 `5 M    distances = {node: float('inf') for node in graph}
  w1 w) v# R$ s* n+ I; ^: Y    distances[start] = 0
: e7 U- Q. |( i2 n  f4 Z% H    heapq.heappush(queue, (0, start))  # (距离, 节点)
% B" v9 E* n3 {3 z4 p8 w
( x5 m5 o, E6 @1 X/ H# h    while queue:
3 ]* }. }$ R8 x% J5 f1 X0 x. D        current_distance, current_node = heapq.heappop(queue)
/ `9 r' y- {7 J' V8 B
& y& n- l8 C3 J/ p        # 只处理当前节点的最短距离
4 t& S- K  |! }2 c% a        if current_distance > distances[current_node]:, x; Z, `+ h( _2 W* W' H' w
            continue
- S4 @) w1 V  _0 X  I2 Y% G* W' b4 u; P2 t- ~
        for neighbor, weight in graph[current_node].items():
2 s, M2 ?, q6 h2 B5 V            distance = current_distance + weight
/ S/ h0 ]( L/ R- b. [
1 I+ K, F* T) d: u0 u/ b. x  h            # 更新邻接节点的距离
- C# v. i' F( t& B4 w4 O            if distance < distances[neighbor]:
% L1 r+ }: U0 ^' i9 W6 P                distances[neighbor] = distance! y/ ?: A3 p. z9 B& G/ C1 X
                heapq.heappush(queue, (distance, neighbor))
- l+ P  ~! q8 |! n/ O9 r, b) l! p7 H+ U5 Q+ O# \6 Z2 z2 e2 a' ?! i% J
    return distances/ M0 B0 @& q* O; H7 ?1 Y
) a7 s$ B0 r1 |  t+ Q
# 示例图
. E9 g- C& F( h' n) }+ Hgraph = {' P& }# q; w9 u: M8 S2 w# e
    'A': {'B': 1, 'C': 4},- v0 B' {9 p1 A% C5 Z
    'B': {'A': 1, 'C': 2, 'D': 5},# p9 f7 J. P7 ?& I; Y/ C
    'C': {'A': 4, 'B': 2, 'D': 1},; m7 s) d( s6 M/ ~1 s% M
    'D': {'B': 5, 'C': 1},: O& q- h; i, x  B
}' A% I9 E! Y. R2 V5 ~0 T

: Q5 @' k, Z/ W  A; g8 _% c* M# v6 Estart_node = 'A'
3 r% C# T% [! _# w" r$ mshortest_paths = dijkstra(graph, start_node)
  J4 `0 {6 ~, |$ v% ^print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
, Z) L9 q6 g. v8 N```
) j0 `0 I) y- [' U
, P) r7 Y" z2 o5 o## 2. Bellman-Ford 算法
/ ]! F( t" C+ n' a) N9 r: a1 C
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
; b0 Z% b0 ^9 Z) c2 A9 S$ [& T% D/ ?
" n6 \/ e! ]& c: T9 s6 H### 原理步骤
. e$ t/ C9 V, N1 y# A3 R6 w0 `7 C: u/ Z
1. **初始化**:4 C' |( u9 Y( d+ Q* Y& P
   - 设置源节点到自己的距离为0,其他节点为无穷大。* h7 [( ^' l8 Z7 g6 M$ A* R( u' V
6 E6 v9 r' L" J
2. **松弛操作**:
% X) }. C1 e8 ]# M. @* _   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。# G) T  G  l% ~1 e2 g/ b

/ `9 t0 V: t: Q& B3. **检查负权回路**:
# d+ b- ~) }# \   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。3 c1 u4 W3 u2 t' Z

% ?4 k6 E1 o: n# f* \### 示例代码1 w; }3 ^* }* Q8 X
' H% ]5 \* L; ~5 ^: e0 j- Z% @
```python
. P' m% K! ^) w) _- e8 xdef bellman_ford(graph, start):3 D0 }: t9 w: O( o
    # 初始化距离
& d4 d4 {) N) w: H6 B, K! S    distances = {node: float('inf') for node in graph}
3 h+ F) y5 F+ ^3 _4 R$ G    distances[start] = 0' O) K/ i9 X2 v4 ]0 @! q! ?+ u% B

5 _2 e; F! h, Q& r$ G0 D9 n& i    # 松弛操作' K( x9 Q2 g$ e& E
    for _ in range(len(graph) - 1):* z0 l- [2 ?+ W6 T
        for u in graph:, c% c6 Y& K4 l! ]
            for v, weight in graph[u].items():" q; T) [; ^2 R% K3 w' `( O
                if distances[u] + weight < distances[v]:
# ^  x  V/ [" {. |3 ~, y9 @                    distances[v] = distances[u] + weight5 B, m1 Y/ v4 ^' c
+ i4 b. H7 T6 i
    # 检查负权回路
, E+ z! D8 H8 M! U& `0 a' M  F3 z    for u in graph:
5 a. H" O/ ]; e( Y. f( m        for v, weight in graph[u].items():
& W$ X9 V& }- x$ F0 D" |! I            if distances[u] + weight < distances[v]:1 L, \) v3 K% E1 K" z$ K8 o) P
                raise ValueError("Graph contains a negative weight cycle")
* \; a9 i! y4 V7 r& E; g  V
; w' Y& M6 M7 W8 K* y    return distances
1 r# \# Z4 ~& P
; y/ U+ w$ r* E/ D, q3 s# 示例图(带有负权边)
# r) @+ h: T( w8 E. hgraph_with_negative_weight = {& V, C+ s6 i: \1 ]$ v
    'A': {'B': 1, 'C': 4},& ^' W! ]6 B/ S( x( i* H
    'B': {'C': -3, 'D': 2},& n7 ^5 x: i" r5 N7 v9 g) p5 h
    'C': {},
5 s; T  c3 J) d    'D': {'A': -1}
" }, ]* {8 o) V; I+ M. Z2 k2 E; H}* l$ g: V- T  a

  i6 k4 S0 e$ h% o/ \start_node = 'A'
8 C) y. y: V7 G  P8 j# w, ~* Wshortest_paths = bellman_ford(graph_with_negative_weight, start_node); T( ?# t$ C. O" U
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}1 x3 z9 g9 W3 `$ P$ n: E! M
```/ G1 p. o8 _. K: v) t. e/ {! L5 o

! h$ E7 O7 k5 k## 3. Floyd-Warshall 算法
, R% ]$ t+ w1 o+ _+ ]8 ?+ s. g) s( A2 {( ^, U: w3 M& x
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
) _$ l9 o# y' {3 N1 N( X% j0 w2 x& \) Q. K& u
### 原理步骤3 N0 d4 ~* e# k  F: a7 k0 x
, T" W. r6 U2 Z* p9 W% `: J# w/ l
1. **初始化**:# K* ^" W  B1 E7 H$ L% l2 v
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。5 X2 n, B1 q8 \( x3 c, }

) ^/ f; U9 G8 @+ y0 ^2 d/ ]2. **更新路径**:
0 ]2 l+ n/ f# \& D: Q: c   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。% L7 O) ^9 u7 I! p' `5 ~

/ V- h! I. M) Y. k! b3. **输出结果**:
# `) P! @" ]; v) g. G4 m* r   - 最终得到的矩阵即为每对节点之间的最短路径长度。) G0 h& H5 E; r( g$ ]. X. b1 e
3 T( P2 S6 _( F, w1 l2 z
### 示例代码
7 g# C+ n$ }) W& N7 _4 |
- C* ^! y2 P1 n& \```python% p- N9 V3 n6 B$ W" u7 ]5 D2 D
def floyd_warshall(graph):
5 G5 q8 L% [, h$ A    # 初始化距离矩阵, m' j1 E8 X8 e( d: z% |
    nodes = list(graph.keys())
, b+ W; _) D% ]    distances = {node: {n: float('inf') for n in nodes} for node in nodes}, d6 E2 Y1 C+ q

$ Z) Q  @  J: |3 `; G3 {    for u in nodes:! V6 K) J9 K" S9 ]9 q4 u
        distances[u][u] = 0
- ~, }  P& S8 |, h        for v, weight in graph[u].items():4 ~$ \+ h7 c, |4 l9 b4 P
            distances[u][v] = weight
" b# G% M9 Y4 b' U& g2 a  b) {2 I$ @7 }3 n, I; w3 I
    # 更新路径& {  f4 |- f1 B
    for k in nodes:
3 J! Q: @0 J- W8 ]" [7 C- M* q        for i in nodes:  _: a! d9 D1 L3 {7 o& O
            for j in nodes:5 u8 Z/ `) y& X' Z# j4 S! A# Y. U
                if distances[i][j] > distances[i][k] + distances[k][j]:1 Q1 B: {' Z+ s% x* Y8 Y' S
                    distances[i][j] = distances[i][k] + distances[k][j]
$ h6 w8 G: L4 n6 {1 ~
& L5 G* B% i& |1 n7 w    return distances- @5 }+ W0 ~( o/ K
6 l' @1 t1 ~/ Y- `5 o" d' v
# 示例图(可以含负权边)
  L- N3 p( v3 t( r0 K8 C* }graph_for_floyd = {
  q: x. T/ q+ B) @& S    'A': {'B': 3, 'C': 8, 'D': -4},) F, w# u. e& t/ x5 z7 ^
    'B': {'C': 1, 'D': 7},
- I( E+ M( G  s/ a1 A% M    'C': {'B': 4},
7 `; m6 F7 O9 p9 J, A. m8 \0 W    'D': {'A': 2, 'C': -5}
5 w' F4 D/ H* ]& ^6 e}- D+ {( i( w' H

# t: z2 X4 B% @4 H8 z) Eshortest_paths_matrix = floyd_warshall(graph_for_floyd)
$ b7 }+ Y8 A3 R) g7 y. N6 Bfor row in shortest_paths_matrix.items():) n3 \. S  x# V: B
    print(row)/ o& i6 X9 K2 a8 J, H- _
```
* B  w8 R5 V+ r; h
  c4 `. D/ m& v9 G( J3 u## 总结
! c# |, R; _; n5 f4 u2 h$ t, {+ V2 N7 t
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
; Q5 `+ z4 Z) R4 _$ }  n, [( l- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
$ Y. X! ~- A( {2 t# P6 m- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。
" a/ E  K$ d% n1 e* `' T2 t+ r& S: @
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!8 y# I- [/ }; U  s6 J
! g8 _+ g9 {" s" N- r

  f! C& D2 h% Y( r, ^. F2 l; r) B

最短路径算法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-14 13:00 , Processed in 0.326177 second(s), 54 queries .

回顶部