QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1189

主题

4

听众

2934

积分

该用户从未签到

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

; u! V+ _; a6 g% U* n7 e## 1. Dijkstra 算法
, I/ x2 P  H! S2 i; @/ O; ^* o, W  L1 F1 S" p
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。" c: n* Y: R- q0 p/ x& s. ]

5 _2 `5 [& a; H, K. X9 d6 Q### 原理步骤
* k# h) b# b' V. f
% ^, C5 H3 w$ ^# K1. **初始化**:! a- q6 m/ d! T$ X  k$ {* b
   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。* d) n9 P+ b# M! u  U/ ]. _4 V) R
   - 初始化一个空的优先队列,用于存储待处理的节点。0 P6 {3 _" W: `; p. C( c2 Q

! H0 ~8 }3 }/ |0 s4 o$ p7 Z2. **处理节点**:
  |/ k3 L' \. {0 \   - 从优先队列中选取距离最小的节点作为当前节点。
4 J7 p1 _# q6 U# D   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。1 V% h; t4 x: t" d+ N$ G5 ~& [- k
# G' `' D* u$ r6 T* j* n. V$ f
3. **重复处理**:
  |; x4 n; {$ M1 b5 U" J  m   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。
6 H* b% L& D, X: E$ l% q
$ b8 D+ H' `3 A### 示例代码
- N! }' u: c! n3 H. M4 D0 P+ l7 y* g/ o7 L: c! a3 l6 y
```python# ?1 t6 O4 u( \
import heapq" L7 N0 v3 }: D

- r  \; H( Z2 Q$ qdef dijkstra(graph, start):: Y& u  P* W& `8 O+ Q. W# B/ z- S
    # 图的表示为字典,键为节点,值为邻接节点及其边权9 S  K6 Z8 e( h2 ?7 u
    queue = []
+ c. D* ^3 c/ ]2 A& F    distances = {node: float('inf') for node in graph}
7 e1 i+ q) @4 Y1 P8 P3 U    distances[start] = 01 }+ `) l- _7 G/ X, ?- r% T
    heapq.heappush(queue, (0, start))  # (距离, 节点)
, B0 Z2 C5 U( |2 Y7 F4 P5 Q2 s- Z9 I9 }3 H' t2 _  Z
    while queue:
5 B  [- D" ^( o  ~        current_distance, current_node = heapq.heappop(queue)
1 j5 k% p- B0 T5 ]' k! V2 Q9 y
; g, }- k4 S8 `        # 只处理当前节点的最短距离
/ d& F( b- q3 U        if current_distance > distances[current_node]:2 w  u* N: N, R% t$ E! }
            continue
# R- \% A3 I$ |$ Y# y; x, W$ `1 X
        for neighbor, weight in graph[current_node].items():
4 H7 g( ]7 ^2 B  z" R            distance = current_distance + weight+ S1 y, P3 L* J  T9 A6 a( E4 s: u
0 c. T: e; y1 e1 k7 o1 e( l
            # 更新邻接节点的距离4 G9 p+ t- W  r; U) a& y
            if distance < distances[neighbor]:9 a: [! v6 p6 Z! ?' T- w
                distances[neighbor] = distance8 u! H3 Q' B7 m
                heapq.heappush(queue, (distance, neighbor)); L* O/ o& m, o/ y" k2 y" E( Z# e
: k% ?# h6 o" B) S+ u6 ]/ W
    return distances
, Q  v. M" E; Y1 ^
! o$ h2 j+ ~  o: M  {: K7 M- q# 示例图, _& N0 i  P0 f, ?
graph = {6 p6 n* `; O: R# ]5 Y' e! J2 ^2 ~
    'A': {'B': 1, 'C': 4},  k% Z; ?7 R* O9 v- ?
    'B': {'A': 1, 'C': 2, 'D': 5},
: H$ y1 f" E9 k6 p( ^" \    'C': {'A': 4, 'B': 2, 'D': 1},
. L+ P7 \3 e& E2 }8 h& j    'D': {'B': 5, 'C': 1},
' U7 S  N1 `/ q2 S; g2 s# z}
% T% P- M4 @( C  t- U+ v9 L
: v' }( ~, g; Astart_node = 'A'
  S3 T) Q/ m; H* q( g  X$ bshortest_paths = dijkstra(graph, start_node)
3 p5 V4 k8 O& B4 A6 m* bprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}
% I& W' P1 @: `6 r* A- y, Q```
; P% W2 K( e( j( M8 Y4 n! ^/ m- U2 s) g
## 2. Bellman-Ford 算法+ O+ R& d( S9 g. {
9 z% C( F( I% s3 G- y, q
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
+ B* L# F, P8 E+ H" Q# O) C# ?+ N5 j' T' X. c1 `' P" `
### 原理步骤
1 H# b1 w6 U0 H: g, g# j& G: n3 V2 `9 ]# h) z
1. **初始化**:7 k; m3 X( |. P# G) L' _
   - 设置源节点到自己的距离为0,其他节点为无穷大。
$ l5 R1 I# g6 s( H7 x5 o2 ?9 I$ e/ V# T2 V4 L7 O
2. **松弛操作**:! a; @2 |/ i8 T
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。6 O% M' H9 Q; f* o1 F
, K' @  y5 L" S5 o' Q
3. **检查负权回路**:+ V1 ^4 k/ b% c
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。7 X9 N# B% w4 f( w6 ^4 h. K5 O
. x* y# f* j! v+ q
### 示例代码
( f# |+ i& o$ r4 c" b+ w2 Q$ s( j# I' u4 g7 X7 Y
```python  U5 c' ~* h: K) y3 C3 |3 M# r5 N* W9 b
def bellman_ford(graph, start):
8 S$ Z$ H* h: ]2 _, F  Y) I    # 初始化距离  e5 u; U& S5 u; d. @
    distances = {node: float('inf') for node in graph}4 {+ h$ [% d' J. @# Y! g
    distances[start] = 0
. J; q. W2 u. [
) Q) d+ |6 \% l, r% H( r! ^' T    # 松弛操作
: s: P- w) Y  O    for _ in range(len(graph) - 1):
' r* `" N$ k6 R+ A( E% H3 T! k        for u in graph:( G' ]- @) I* P- u
            for v, weight in graph[u].items():- z& `( n0 m! ?7 {, N. H
                if distances[u] + weight < distances[v]:
2 A9 a( d2 J3 o% w* x  H( J  Y                    distances[v] = distances[u] + weight5 |# ?, D3 Y0 }1 a" B

9 Z3 `/ J. T! b, z    # 检查负权回路
4 i( v% e0 w9 R% f4 ~1 Q( Y2 _    for u in graph:
2 ]4 |" V4 U" n: e. d7 i  I1 ?        for v, weight in graph[u].items():' A% K! |5 _. e; ~9 Z: o6 m1 ]
            if distances[u] + weight < distances[v]:) f" M/ y9 W/ U2 @. L8 I5 t
                raise ValueError("Graph contains a negative weight cycle")
1 L+ R) N' L" B% p7 q/ S* k& k4 D" G# Y9 T9 {/ ^. N8 V
    return distances
, C+ @& A* K& ]& {6 |
; g( v) \4 _2 w2 ?* B( S# 示例图(带有负权边)- _0 q+ K5 w7 y
graph_with_negative_weight = {1 u3 t2 f0 p( Q; f6 X3 ?
    'A': {'B': 1, 'C': 4},* \- [5 E3 V6 c0 C( Q3 }" L5 t
    'B': {'C': -3, 'D': 2},- t+ C+ p( q5 H* ~$ j0 R
    'C': {},7 N5 K9 ]8 f) a- q5 x
    'D': {'A': -1}
  l( h3 N  l! e7 W* x; q}
: Z3 I, A4 \0 |( r2 M! U6 h5 T: L: }3 J$ o0 i+ V
start_node = 'A'
7 ~9 V, h& L8 m7 w5 @; Bshortest_paths = bellman_ford(graph_with_negative_weight, start_node)
% r! c  z0 @  e2 \  o/ }print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}0 Q9 g0 a* w/ y) f8 |2 _% q7 L
```! Z) [, A0 q; X$ K5 |6 a

/ R6 E1 r& D/ O8 p, n" S  n, b$ p## 3. Floyd-Warshall 算法: l3 Z8 _- G, R

' A# \9 B/ r5 d4 H4 q* X1 a5 j6 wFloyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。. t5 J& x5 s8 G( C
4 L7 P" X! H3 K% ]0 B
### 原理步骤% R0 e" E7 y8 k: S' A3 o6 w0 z

4 Z/ d3 G8 r7 e$ k1 x/ O1. **初始化**:
' e# q1 V7 t1 \3 d2 |% ^   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。
5 I8 t2 n  z6 b& z. S2 j8 x5 V1 I
) K  z5 v% q' {2 g2 I0 y, W2. **更新路径**:
* `' a# ]% A9 O1 H+ K0 ~; k2 h   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。3 H, W) D% Y0 t; S3 X+ i
8 n6 ]; _) A4 G% g
3. **输出结果**:( A3 W: E. S2 e9 Z3 A
   - 最终得到的矩阵即为每对节点之间的最短路径长度。
, F" X& l# z# ^0 ?! U/ F' I, R
. v3 [4 \: H) @" u8 g% P" s' k2 F. B4 G### 示例代码
! O+ }* {% [/ ^# E+ O
! }. [6 v/ j% s+ E! @" ~```python2 w( x0 {( _  A# d" e
def floyd_warshall(graph):
; Q* p' n8 y" {" p    # 初始化距离矩阵- Y& l7 [+ c" p# j1 {$ q
    nodes = list(graph.keys())
0 J9 e& c( }6 q( Y    distances = {node: {n: float('inf') for n in nodes} for node in nodes}; G% l7 {  h; p/ X

: j1 W, M/ c3 O2 F7 ?( d    for u in nodes:, z) W! X  V$ O: l( F4 j+ G7 A
        distances[u][u] = 0
5 k  l  O1 W2 D3 h" u  g        for v, weight in graph[u].items():
2 L2 U4 r1 Q( n" L0 {# n* Y            distances[u][v] = weight5 S& g. B4 c0 J$ @0 {
+ Y& ?+ x& G4 U: R/ X" k
    # 更新路径$ ~% ^7 n1 K8 M# Q+ O" _; c" t( O
    for k in nodes:
/ e) I4 T. W2 Y0 m6 A        for i in nodes:- S  z- \: k0 d- K# B
            for j in nodes:% J9 P) p4 _. b7 _$ W% A
                if distances[i][j] > distances[i][k] + distances[k][j]:
7 a" A" `8 a9 W                    distances[i][j] = distances[i][k] + distances[k][j]
1 J" B0 N! y7 a5 Z: o/ y' C/ R% p9 X' N, K! v7 D: b
    return distances9 ]- ]8 K1 F! a. ]  W+ h
3 c$ {6 b8 J# R7 t
# 示例图(可以含负权边): q9 `5 z' W8 y3 N
graph_for_floyd = {4 S+ @1 e: y, x9 |
    'A': {'B': 3, 'C': 8, 'D': -4},# O; O/ F9 k  \$ J5 ~( Z3 H) M
    'B': {'C': 1, 'D': 7},& I8 ?' a% h( b3 m! L8 ]8 a4 i4 S
    'C': {'B': 4}," c1 d0 g" V, m5 X7 S
    'D': {'A': 2, 'C': -5}
/ r  D) \5 P7 \! S  {0 S}8 {4 W# U  K0 j1 R1 W2 o

9 |7 C: o1 G+ K7 Pshortest_paths_matrix = floyd_warshall(graph_for_floyd), v; _0 w6 l9 ]# H6 H
for row in shortest_paths_matrix.items():$ x4 }; j$ v6 V, ^
    print(row)
3 ^! k- d% v, z, c- B```1 \5 v6 X- Q* U3 Y8 J' w, H3 a; Z
: F' }! Q: ?4 ^/ Q
## 总结
% \7 Y. i1 V" a+ t0 ~, v) x* R' R' t) M1 Z
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。* L/ x3 W/ W, Q- Z
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。% g8 U' x7 Q8 c, F6 {3 k& J9 o- ]% L
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。& {5 q. u3 U; B- @6 w" Y5 r

- [, Z1 ^' ]  @5 \! O不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!
- V' J: T8 ?: \: s$ B: k5 B# m2 [6 F

0 U% x8 A0 w" N& I* W
' r7 B" j0 y/ C# [! X9 B0 i

最短路径算法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-11 05:44 , Processed in 0.773884 second(s), 54 queries .

回顶部