QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1189

主题

4

听众

2934

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |正序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
1 t. \! H% @2 F: S& \, ]
* e( b' `& s" j## 1. Dijkstra 算法
* @% K; b* x; q* E# g! |" J% u5 y3 m6 W, H9 _$ t, U" ]
Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。
: Y2 d  Z1 v: w' Y( c
# b* [* i% J( z2 |8 @" H: u### 原理步骤1 l- q& o: a9 i$ e$ D- M- E/ O

1 u6 S, h5 C* v1 f3 d2 c1. **初始化**:0 k; u! s, u/ `1 J2 c* E5 v
   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。
0 _. g( ~/ H, D# ?  p   - 初始化一个空的优先队列,用于存储待处理的节点。
5 i3 J% T% ~, f9 I. C5 P
, g# s; Q! j1 f& @9 `2. **处理节点**:
4 `3 B7 V- t' e# y8 P   - 从优先队列中选取距离最小的节点作为当前节点。0 b8 a0 i6 l/ Q/ ^8 e
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
5 g0 R# y1 M4 N' ?* C6 ]$ u  A# g3 R& J. S/ q
3. **重复处理**:
7 ^! D9 F0 l& p' s! a$ Q   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。  j; p/ l0 G# E; ^# C( v( y$ g

! i7 c: u  P2 Y+ R### 示例代码
( q' K' C: A+ k- F8 Q( m' o  k' q* c# x1 }6 ?; I
```python
& \1 y6 u1 x2 B8 simport heapq
6 k# I, }8 [1 }& `/ {
, y, s4 @% K( O1 fdef dijkstra(graph, start):
# B3 N6 G2 G5 D4 ~3 c7 b    # 图的表示为字典,键为节点,值为邻接节点及其边权
2 \+ f& d0 r) q7 D    queue = []/ o; D/ p. b0 d. r" U% b4 y
    distances = {node: float('inf') for node in graph}
3 ?) T) w; \6 e# k; x    distances[start] = 0
6 p3 q3 U2 W( J! M& L0 o    heapq.heappush(queue, (0, start))  # (距离, 节点)
4 a( `, d4 `* m  q
* U* _$ q3 M/ z* i6 v% Y2 Y0 ^    while queue:
, ?, x' K- I5 l1 @- P        current_distance, current_node = heapq.heappop(queue)9 `" l; @0 g0 ^7 B! k3 S" M  X4 l

: e( m, Q# w' b; L" B8 C        # 只处理当前节点的最短距离
6 @; a4 {+ h& W5 h        if current_distance > distances[current_node]:1 f3 f$ |7 b, u# x; a
            continue
! C4 |; i) B' y9 t* ~
+ ^# A8 Y( J( Y0 b9 V! H        for neighbor, weight in graph[current_node].items():
9 {. N: m( F+ z; j: g! s) U5 q            distance = current_distance + weight+ P  `% Z  g, C) G# A$ F3 M- J* {
# @1 Y0 \8 s: s9 ?/ E  h  L. o$ i2 `
            # 更新邻接节点的距离9 Q1 P  s! F- b* x
            if distance < distances[neighbor]:
2 s+ c6 X$ d3 |* f9 r# e                distances[neighbor] = distance" T$ S7 E' d4 W5 \" q  _4 C  X: `
                heapq.heappush(queue, (distance, neighbor)): y- O( F$ C: g: k% z
2 H, p& t0 A* W, H6 `7 c
    return distances
0 W6 }% q+ f, r9 W
/ o0 n+ A" G) y* H7 Y& k$ y# 示例图- w% Y. ?4 r9 c0 H
graph = {
6 H- x& D& p4 V% e9 o    'A': {'B': 1, 'C': 4},
. M( Y# X+ Q* j5 I    'B': {'A': 1, 'C': 2, 'D': 5},. U% B3 z- r  K( ?" O+ r
    'C': {'A': 4, 'B': 2, 'D': 1},
8 Q3 `$ V2 w) b! [    'D': {'B': 5, 'C': 1},* ~; I: E& n# r0 I2 W. Q
}
7 f# \  c4 ^% {6 H& {- k9 n4 N. H% U" ^
start_node = 'A'
8 v+ B5 e6 h3 W4 w) N4 @8 Y# S5 G0 C" f1 fshortest_paths = dijkstra(graph, start_node)
3 b, }. C) _, G* J0 L/ j; Sprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}8 P1 a3 J& x( N" B2 F& X
```1 o: G; H6 r& _
  q) w  L& q3 Y$ X1 e, u( T
## 2. Bellman-Ford 算法
+ y6 [, F9 E; @* O1 p2 J8 `! Z  G* v8 V  u
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
  V* q' [  o! L5 B; U& I" t3 |' E6 u2 i
5 P2 h  r  d- m" V0 Z### 原理步骤
' c2 v2 W  A3 S( S$ A& J6 g) e1 E6 x8 `; W" u3 @9 ^0 [
1. **初始化**:# |. X& S1 n1 K: I
   - 设置源节点到自己的距离为0,其他节点为无穷大。
% U8 e9 Y/ c, H) N* h  d1 U* I, H! }* ]8 |" M" C
2. **松弛操作**:
- g6 Z. B: B& g1 @/ ^   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
2 P( g+ T! V& f! `4 f
7 _/ U& G/ Z9 s+ x1 ?3. **检查负权回路**:
. l2 I; ~8 L/ v( s0 F7 x  K6 }, m   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
4 G  V3 @# L# K3 c5 Y  d' J3 y
. I; N/ h- d; r### 示例代码
6 L5 ]$ t$ @0 r  q! _0 H9 h; b2 M) F8 V2 o9 j, l( N
```python) k! m6 Q  g! ^- ]: R
def bellman_ford(graph, start):
/ h1 T& P3 U" ^  x2 }1 |$ p    # 初始化距离
2 A& M' t( i/ E1 d    distances = {node: float('inf') for node in graph}
5 q- l  c+ h5 S1 R; b    distances[start] = 0! v4 s  w& L8 r) q+ z$ }. I: w9 u* U

% b: a: l" r+ s( R, J    # 松弛操作
, q2 ]9 {: q. g4 v, T0 N+ u- ~    for _ in range(len(graph) - 1):5 O  s4 S0 U& u. T
        for u in graph:
2 G+ ~+ l  U% d. n            for v, weight in graph[u].items():
; W) X: Q6 S. |3 p! d4 V7 d4 Q                if distances[u] + weight < distances[v]:
  i/ ~+ M. U& f9 T6 L; Z                    distances[v] = distances[u] + weight$ R, N5 i! ]( q- [( ~/ Y
/ B7 L& Q0 I" K1 s" b
    # 检查负权回路
: n7 w5 \$ s! S/ V    for u in graph:
5 m: E" {( e1 l" a5 @        for v, weight in graph[u].items():2 N0 y! H  V! p: [7 x* x9 O+ Q
            if distances[u] + weight < distances[v]:. s9 d* T7 U! V$ M/ {+ v
                raise ValueError("Graph contains a negative weight cycle")+ s6 L- h6 q* F: {0 l* u
0 w5 G! u  L6 A, q5 o7 d  h
    return distances
: |$ t) ]5 g) Q: z( P7 K, ~0 a+ |, x# O% J& ]; ~3 O$ P% E9 j+ I3 R; I- f
# 示例图(带有负权边)( Z* h6 h3 q8 ^5 ?7 l+ i6 m+ J
graph_with_negative_weight = {
% G" G' i. B' V4 s    'A': {'B': 1, 'C': 4},
9 u3 G1 p; c& O, A5 a    'B': {'C': -3, 'D': 2},: w; X* d$ Y4 d, o7 m4 ^
    'C': {},
* ?) L6 w9 }& }6 g/ J/ [, l    'D': {'A': -1}' v5 O4 h/ P* T/ [9 x9 |
}* f8 ?: b* O7 U) K( h& J+ d* O( h

6 C6 S  {- Z1 v  G% S& A  S' lstart_node = 'A'1 D( S' i' u7 N4 c
shortest_paths = bellman_ford(graph_with_negative_weight, start_node)
9 g5 |: j- l0 s) mprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
$ u. ^: r, L  [- k```
6 w- J) {/ ~% H$ J& O$ a$ u0 i/ S8 `+ o
## 3. Floyd-Warshall 算法
. x( U0 @% M! _6 a) |; E( |# K  X+ L0 ~
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。0 v! T. a* ~. V5 h7 H# b/ }# o# L
* e6 z( V% ]0 A$ j/ a
### 原理步骤
0 K; M& X+ f2 s1 T
; i1 H5 M1 G, u1. **初始化**:
/ D$ W5 ^2 D: S  Y2 {   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。
: d" A( K  Y4 S0 h' Q  M* ^7 M* [$ ?- r2 g5 _- o
2. **更新路径**:
& o" h. F2 o" O   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。
; Y& a/ a" k+ G! _
6 t" _2 i4 z+ ?6 K! Q! m! @$ {3. **输出结果**:
( _& O, [0 m0 [% ]$ T. @- Q   - 最终得到的矩阵即为每对节点之间的最短路径长度。& |7 g3 P3 M3 @+ D: z

" M: [. R& v0 e) s( R% o### 示例代码
/ ]' r4 {4 r" x- }. m) o# E  V6 B! ^& x* \2 m
```python' G( k" V$ D( x
def floyd_warshall(graph):
+ V3 g  u7 ?; W0 h6 O    # 初始化距离矩阵  j" |9 [. n+ O' F. P
    nodes = list(graph.keys())
5 }" n# G( R6 o. w, V    distances = {node: {n: float('inf') for n in nodes} for node in nodes}7 y+ e7 k9 x9 \* V4 M& `* S/ Q
# K2 M  y' r1 o* |
    for u in nodes:
9 \$ R" i$ ~# B" `! B, h        distances[u][u] = 0
( L2 g' Q1 p8 p& \! Y5 r, h& ?& [        for v, weight in graph[u].items():
* I4 r" `/ O+ p2 m! f, o% u1 c            distances[u][v] = weight
9 s1 z6 }% T4 i. U2 r
; W+ [( o4 w& b# V    # 更新路径
$ T* k0 \9 ~2 {* d) d    for k in nodes:1 v! f' G+ C- u0 H% j
        for i in nodes:
2 }1 f, Q8 ?5 a' [1 q( |: S5 G            for j in nodes:9 }% Z1 l% W/ u' h1 o
                if distances[i][j] > distances[i][k] + distances[k][j]:
. c" N5 u& T; F; r4 p                    distances[i][j] = distances[i][k] + distances[k][j]; w7 P) g9 A7 |0 Q! M$ Z! h

; F/ g' i& J# M! {" T0 {    return distances
& r# z+ b* G; V; I+ f1 V
6 J: T# J; C4 X, s, ^$ u4 w# 示例图(可以含负权边)
) j! o- I, x! E8 p" mgraph_for_floyd = {
& @! i$ j, _, T4 E& @    'A': {'B': 3, 'C': 8, 'D': -4},$ @- @) N  H% R: Z
    'B': {'C': 1, 'D': 7},
6 f' ]& k9 v- C, z( [7 T& T    'C': {'B': 4},2 ?! \. t' f: Z  B
    'D': {'A': 2, 'C': -5}. |' J6 N5 H) j- o
}
% A: t$ V+ G$ K/ Y4 V
2 J. L$ X! `7 a0 e, d1 b' v' v, L) dshortest_paths_matrix = floyd_warshall(graph_for_floyd)
( P5 C* t% [, ^8 ^. _' @/ Hfor row in shortest_paths_matrix.items():
3 ]) a. O% c4 ]6 h    print(row)
% Z2 J) H2 M: _7 N. n4 m4 K```
/ @7 p: X) x) }# z! f; W/ Q: L
## 总结
& M" i% l. `3 I+ N9 N  B5 Z
7 b# g! r( L8 x( s3 d  s- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
6 y( n& s0 I& Z0 r1 \# x7 ~1 L1 P- d- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。5 b& J* P: K, U4 }
- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。
' T9 z: c) A1 L; }, C% B. G) {! s4 @+ {: a$ J: K( |, M/ E
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!0 i/ E: h0 u/ t! P. ]( g
* h$ |1 _$ L. y( F: ~
; l) Q: N& x4 @* l  O* N2 Z2 T! ~

' R3 G6 a/ I3 O  P5 h% y3 P

最短路径算法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-12 05:35 , Processed in 0.402025 second(s), 56 queries .

回顶部