QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1188

主题

4

听众

2931

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。0 q" ]3 L: l/ m( C& H! z' @$ X2 y
3 B( W# G; L  N6 H7 \! p9 M: v
## 1. Dijkstra 算法. S, K/ ^" g5 E: _* f7 c

8 l6 m- O' I$ [: J1 ]% yDijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。
" g5 F7 u0 e5 Z- g9 }5 [4 M  Z) ~! v# m# y( A5 z% h) K
### 原理步骤
$ L8 o: a9 g" T: H& x: P
5 T  X8 b0 j5 X( x9 }, D. k' F* p1. **初始化**:
* {4 r+ [' g% l( U! Z- m. o* i   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。- Q! _% Q, m! d9 j: Y4 f: Z: T8 o
   - 初始化一个空的优先队列,用于存储待处理的节点。
7 V8 U( C: t, K) Q2 K1 [" x7 H5 ~2 c, Q7 [
2. **处理节点**:
' K2 h. \, f5 y: U   - 从优先队列中选取距离最小的节点作为当前节点。- Z# V- S1 l  C% z
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
' [* t- y7 ]) M
: \  T/ D5 i0 ?3 H3. **重复处理**:5 N' u8 X/ _/ l, i( i7 h) N
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。5 S9 C" F( J1 m/ [: ]* S6 M

% R7 k* C) a" F8 `  v, i. e### 示例代码
+ g5 n9 _: ]6 B2 n/ o. L: r
$ h4 L( W- k* T2 V1 {+ D) f```python  z5 ]3 b0 [, b& `
import heapq
/ ?1 y4 C0 ~$ |' u! j! Z! m
' {' P* H( q& |  u" Xdef dijkstra(graph, start):
9 e" Q7 x8 Q$ J+ k, k9 e. x    # 图的表示为字典,键为节点,值为邻接节点及其边权
  k  a4 l* Q7 y- d; Z( w* d    queue = []' T3 g( L, T" V* y# K
    distances = {node: float('inf') for node in graph}
# p$ @9 K8 Z: l6 c    distances[start] = 0
+ @: c0 O2 B. c; ?4 P+ V# l8 ~# o    heapq.heappush(queue, (0, start))  # (距离, 节点)
6 J. f( o% k% X+ `4 H* G5 M
6 s7 {) Y' n. B    while queue:  m$ W* }, _/ f5 q8 \1 \& a
        current_distance, current_node = heapq.heappop(queue): c0 _  U, d9 g9 g6 P' N: @

  c* v$ W7 E5 U1 U! _( f3 s) x5 R        # 只处理当前节点的最短距离# p" W; \$ q& K
        if current_distance > distances[current_node]:% y; @& G6 J3 ~2 Q" Q
            continue, t1 V# F( Q# _: r6 C9 l
3 A. W6 d- U/ o
        for neighbor, weight in graph[current_node].items():2 ~5 Q8 P8 e: A9 Y9 R5 X1 w: x
            distance = current_distance + weight9 {; s  P- c: W& `
- ~& d. W( x9 z& R& d% G' T2 H
            # 更新邻接节点的距离
1 p& _4 T, r0 ]0 y- K            if distance < distances[neighbor]:
/ c  r5 R5 c& W( g+ u; @4 m                distances[neighbor] = distance- g& a" f1 e, t3 k
                heapq.heappush(queue, (distance, neighbor))2 O- p7 y  k, T5 G8 k

! {+ j3 r) L0 F- i    return distances
* P: E) E1 J5 }" L) b8 a7 l7 A7 y2 V, _6 B
# 示例图
% ?- \( R+ a- S9 i% z, b6 tgraph = {
& m( E5 b/ O/ Q5 [    'A': {'B': 1, 'C': 4},
* h8 a2 k5 ?, o* H: F1 E- Q: c    'B': {'A': 1, 'C': 2, 'D': 5},, u1 L9 t! k' [1 Z& z+ [
    'C': {'A': 4, 'B': 2, 'D': 1},- ?+ J# U. x- b& S( V
    'D': {'B': 5, 'C': 1},: y  Z  E* K4 [, O
}% h- z; _; `2 D. X% C5 M! J
4 N- S. Q" M! Y& |' q
start_node = 'A'
2 R( a2 ]5 l# }* K8 Tshortest_paths = dijkstra(graph, start_node)
4 X; P5 S. c$ A$ d2 Tprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}% ?' k. _& |& h: C! }! Z
```- Z- v4 W8 I! L7 {2 s. [
6 f  S# A! V& F3 S
## 2. Bellman-Ford 算法8 _2 _  `: t1 N$ P* ?: d6 y! D4 D

3 _4 {- b- k  T* A( BBellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。
. ?8 z8 m, W; s% F% T) k: @% f. K; W  U
### 原理步骤
& P& `) a$ o8 b" m+ y( r3 [. R" _" E- I2 q8 P
1. **初始化**:# J( Q" f: u9 Z1 w7 ^
   - 设置源节点到自己的距离为0,其他节点为无穷大。
4 X0 c: F* Z+ l7 W
/ y3 L% V2 ^3 ?: }2. **松弛操作**:" s  S2 B, R- B3 e  {" p
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
" g' V$ F/ {$ Y7 [5 H: Z) `/ A; }( M" Z- K
3. **检查负权回路**:6 s, h2 N. }& C
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。
! s1 H! a' e+ r( Y0 s  Z8 J
% b3 j4 ]7 V, x/ Z/ n4 A### 示例代码
: ^6 _6 z9 g6 t# ^/ k! i" t9 ~4 G; T# a: @! E
```python6 x7 E' Y. R0 I$ g5 E
def bellman_ford(graph, start):: p! h+ H# l: {9 w* b9 {
    # 初始化距离" p. e2 x6 u+ d$ r3 X2 [4 j1 }
    distances = {node: float('inf') for node in graph}
4 m) a4 y3 y" J    distances[start] = 0# H6 M& Q6 I" Q/ F
: Q, v0 F4 O9 {6 e8 H( |! m
    # 松弛操作
3 u! S+ P& |7 T% |0 S    for _ in range(len(graph) - 1):8 d: y  C& s$ G4 C0 a+ ]) O6 c
        for u in graph:/ {; v$ Y4 }/ ]6 t: m& ]
            for v, weight in graph[u].items():' N9 `1 L5 G2 a6 C, H
                if distances[u] + weight < distances[v]:
2 x( m  c) t$ e) S) W                    distances[v] = distances[u] + weight# u: _" ^1 p1 n2 y4 G/ ~
; A& [4 v; @2 P1 f' l( o
    # 检查负权回路
* Y2 z" j- x* E/ D! m8 b+ j    for u in graph:
( b* F0 P7 d" a% l( D# c1 \        for v, weight in graph[u].items():
6 Y9 h0 I3 n7 T" X$ {$ o            if distances[u] + weight < distances[v]:
! T% i7 R" f1 `# a: r1 _                raise ValueError("Graph contains a negative weight cycle")
6 D* u$ C: w0 m1 C8 S0 g: H$ V5 n$ ~& ?+ Z) q/ F9 n* c% Z: u
    return distances
0 Z9 Z& z: i$ X& A' W3 h- r& V0 G5 X/ p; A7 |. @
# 示例图(带有负权边)( z3 W+ X# ^6 Y
graph_with_negative_weight = {
) j* S) S9 |( W) \: U    'A': {'B': 1, 'C': 4},( `  Y9 f" y* n- @  j
    'B': {'C': -3, 'D': 2},0 W/ f! D+ Y6 {3 y6 K5 {
    'C': {},
" j, p" a  Y% q& h    'D': {'A': -1}* X6 d) T0 u  D1 [
}
8 @5 {8 G3 @- b1 m* K9 W- ^) `6 c6 o' E+ {* H- A' O1 Z1 T  e# B5 c
start_node = 'A'+ y" f" x9 t: s; `7 ]. ]
shortest_paths = bellman_ford(graph_with_negative_weight, start_node). @; A5 L: x- X1 B' [
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}* |9 O& j$ Q, d7 A3 K9 V, E# X" d
```& q$ Z! c( U( A% \4 }% c5 q

; J- \* y. S( A; w- S## 3. Floyd-Warshall 算法+ ^% i2 ]7 |7 T+ D; ^  L
/ @" U' |6 n  o* d2 A
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
. H* |: f% }7 P1 |/ `  g' G# H) o  i
### 原理步骤
; g$ G0 u! H) w4 v- s" u. g
) e" ~% j" [2 C3 ]6 }# U! O: R& E1. **初始化**:
' T4 }' S( n3 }' |   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。
" y* {  @  R4 p2 w4 \9 Q; E+ s. O6 O$ {+ n$ L
2. **更新路径**:
* J! f" _! }0 v- [) `# u   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。1 h4 V5 r( f; s9 M; }2 T- q: F3 ^# U! m, g
% t& p) T4 ]6 \8 Q+ G
3. **输出结果**:6 K0 S$ |. ?6 i" d; r( f
   - 最终得到的矩阵即为每对节点之间的最短路径长度。" t3 s1 S7 }2 C

2 C: l4 W) \4 D) o### 示例代码
$ J$ x/ w  R/ G# r  X8 o: k& a& P; O/ @2 }2 t
```python
$ F& X# d8 O# v7 n$ L/ `6 C% j6 }8 L& kdef floyd_warshall(graph):
8 @0 }( `0 c/ Q( y4 T: E( u    # 初始化距离矩阵7 z0 X. x* p' S# ?2 ^
    nodes = list(graph.keys())% T9 F/ O# m9 u4 N9 W2 x7 x
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}
& |. S1 ~. ?6 l& p) F6 K
( D7 x& \' L, f% A" n) r) e    for u in nodes:/ t/ T% }2 z3 n* n: f, I
        distances[u][u] = 0' `6 N+ W* m$ ?
        for v, weight in graph[u].items():
3 N/ t! N( W& w3 \& b$ C            distances[u][v] = weight' m  x. ?% B: d4 T
' r" h: X8 Z5 F( H1 b0 V; N3 r2 f
    # 更新路径! B, \  |- x) m8 c+ |! D( N; ]2 k
    for k in nodes:
% e1 Z/ q# ]( M) z2 q        for i in nodes:: i) ^( ?  Q1 p- g
            for j in nodes:
3 p- {* f7 h# _! @5 }; ], Z7 T3 {                if distances[i][j] > distances[i][k] + distances[k][j]:
+ ?( r8 H& p- T; c7 f$ i% M                    distances[i][j] = distances[i][k] + distances[k][j]0 D- h6 f# `9 L) ~7 c

- C; o4 O8 K& ?' V4 p; s% e# S8 c. q    return distances2 F7 D6 ]; S8 ^! v% q
# f! D( N' U* B5 J* G& l- x
# 示例图(可以含负权边)% O) C( Z4 i; @0 ]/ ~8 ?' E3 d
graph_for_floyd = {
1 m$ i2 F- B5 b) j6 @    'A': {'B': 3, 'C': 8, 'D': -4},
  _/ D( Y& _4 m1 Q; E& b- G    'B': {'C': 1, 'D': 7},: X! Y/ `" F- n% K: e) g
    'C': {'B': 4},: I9 i# ^+ P! b, X! T
    'D': {'A': 2, 'C': -5}
3 k7 L3 x3 z9 }. O}
% r& N% X1 k9 }- E8 n* L1 W: C7 I; F) P8 i4 Q, J
shortest_paths_matrix = floyd_warshall(graph_for_floyd). O, z/ i) b; J* B! `" s
for row in shortest_paths_matrix.items():
# J$ O( I5 S% J$ V% a! f    print(row)
9 o- U/ K0 ?% {3 b+ j```
" N, O1 Q) H  Y; R' S. G" h3 L/ j5 _) T
. a5 Y& b: N5 d; |) `) h## 总结7 d9 i! E0 B8 U( B; A
/ n; r5 L6 e& i, W6 t% g
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。# X5 S$ v8 e0 Q
- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
& c- {8 U% ~8 ]& T$ |- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。% ]! e" {  X8 b2 j$ k8 [
& X  a4 s! z+ ]* d
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!% p5 F4 B% C0 I; w1 i
( L! l* D% C) Q3 M/ ]+ [
- q: `9 Z7 B+ b( e
: g" C' H% T) E. S4 X8 h- \% K

最短路径算法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-5-25 19:27 , Processed in 0.414917 second(s), 55 queries .

回顶部