QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1198

主题

4

听众

2978

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。3 p& e# D9 E7 o5 o

3 }8 M9 {0 X+ P% ?6 d9 f! Y## 1. Dijkstra 算法
; o, V" [: K1 |0 F; E  S
6 f, M0 u0 X3 W4 _& ?  WDijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。
" {, W0 b# t- O2 i+ d+ {$ m7 Z9 \( h6 r. t6 T8 ~
### 原理步骤
6 k6 G0 v/ M- U. B; ~8 N+ |5 i7 _! C
1. **初始化**:
( ]; L. P* X1 R, j" I& M   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。
4 Q4 ]; g: |/ S% }' N0 J6 [; L   - 初始化一个空的优先队列,用于存储待处理的节点。
3 ?, L- v7 c8 w9 w
1 l* E1 n9 B% y  r! V2. **处理节点**:0 n$ K+ t/ N; ]! s- A( Q; e7 U
   - 从优先队列中选取距离最小的节点作为当前节点。
% Y( i* @: L% G* a- v   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。
! y0 O: o; I; c$ M# U$ D3 K4 C; N( X7 J& ^& |9 ]( `7 ?& a7 z
3. **重复处理**:' U" X. P' l: b- i; S3 r" c7 K
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。) ]8 c; e) @, Z& [; _+ R! W" ^, }
. K+ d$ P1 I$ B6 |: F4 V
### 示例代码5 X6 B# h. [/ p9 a2 Y

' m/ l/ @" z" V- I```python
8 V& y- Z5 U- {* wimport heapq
8 U( ~0 i' d9 Q- @8 ^8 x; \" X5 A0 q
def dijkstra(graph, start):
  f; q; k3 r6 {! J6 M    # 图的表示为字典,键为节点,值为邻接节点及其边权
; h& ?6 X1 l8 \* Q+ s) s' d    queue = []9 o7 u) g; s1 {
    distances = {node: float('inf') for node in graph}" U9 K) m) ~+ a0 C* b: a7 `" q
    distances[start] = 0
' [  @( {2 x5 f4 Y9 I; C+ @1 |  `    heapq.heappush(queue, (0, start))  # (距离, 节点)" W9 @* ~$ j& u% o) s2 j5 D

0 x7 C* s+ P& C    while queue:  u9 L  j0 r) _5 Y. E+ n
        current_distance, current_node = heapq.heappop(queue)! s$ [! O, ]/ L; g/ z
* \& _( X" y$ C* B, Z
        # 只处理当前节点的最短距离/ X$ c, g1 \/ G/ f" g; O
        if current_distance > distances[current_node]:
2 J5 i& M, D, g/ n- d! T+ X            continue
# K2 D4 ?! A# \% J; ?  U) u5 K# E( D. ?* r4 e5 R: I( h% D1 v
        for neighbor, weight in graph[current_node].items():
2 f6 U% p2 V5 F/ D            distance = current_distance + weight, V6 w$ a9 P6 |. X% U/ A

. k1 Q) K1 p7 l            # 更新邻接节点的距离
+ G- a( U- B: s            if distance < distances[neighbor]:
+ R; \0 w( t& F                distances[neighbor] = distance3 t5 P. i' `  ^: V
                heapq.heappush(queue, (distance, neighbor))3 J- f* E2 J; m* I
* \" \  H' b7 Y4 i( x
    return distances7 D/ H8 s9 S, y9 a: F1 y  j: G

2 ]- E% l2 n7 L2 M/ t# 示例图( g% J% U; e# I
graph = {
1 ]' V: M  h" ~; K- V1 X/ G7 H9 i    'A': {'B': 1, 'C': 4},
: B6 S5 ~& U, k9 Y; W& x$ Z    'B': {'A': 1, 'C': 2, 'D': 5},* ^. O8 m5 J* H9 e
    'C': {'A': 4, 'B': 2, 'D': 1},5 U6 e/ t/ l) _. q/ c& h  J) N
    'D': {'B': 5, 'C': 1},
! h) l7 S& B4 K3 Z  P}
5 d5 W7 x+ E' D4 _- E1 m
4 V& e9 N- r' A% n) d8 m) Astart_node = 'A'  n+ t) U% K, S6 M& H9 H
shortest_paths = dijkstra(graph, start_node)
" @0 O5 i7 Q$ k- uprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}9 u: J9 j- c1 ~# |2 S: e7 J; }
```/ W+ k* W. L8 c- H, ~' G0 t
7 e+ p' U+ S/ y& f
## 2. Bellman-Ford 算法+ c0 j3 c( R4 r/ t5 f
2 d' B& [6 a8 Y- T3 K; j
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。) t: h0 w4 g( Y7 j/ u7 g& |

1 H' v5 l! c& @7 z5 H& A' Y1 _" {### 原理步骤
+ y6 @6 @6 N0 N2 h) ?7 S4 _8 Z
1. **初始化**:  V0 ~8 y& u7 Q; {
   - 设置源节点到自己的距离为0,其他节点为无穷大。+ j1 ]9 Y1 j/ J( K  |! v
2 N/ R+ r6 ~9 g; m
2. **松弛操作**:
- Q' c; J; j+ z: n   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。
) x  J5 I3 K% b% }' U$ k( Q: J9 H6 N% ~
2 S+ C8 l3 I7 r$ ~3. **检查负权回路**:
3 |8 H0 O7 t. g4 R   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。" h# b& D" q4 X; l# N' x# k7 x

6 t5 b: M, `0 z4 K- A4 a### 示例代码
* H* [1 l% o8 N3 G- d0 e. X- a6 M. o# F+ T- e7 w
```python6 N7 l' h9 Y! m
def bellman_ford(graph, start):* f" x! d/ \- d: l- \9 J, T2 k
    # 初始化距离
: m3 @% g3 r8 ^0 i0 @$ m    distances = {node: float('inf') for node in graph}
: ~0 ]4 @  s2 ~5 m/ n/ P8 {  b    distances[start] = 09 R! N, }* i: P9 c& b
9 u9 X4 ^$ t+ h
    # 松弛操作
6 v5 `  }% i8 s8 W    for _ in range(len(graph) - 1):
; U4 G4 Y7 r/ M        for u in graph:9 Y3 Y, G5 t0 s8 |1 [
            for v, weight in graph[u].items():
% f/ z( a( D  t- u' d& t                if distances[u] + weight < distances[v]:3 P5 [! n  R( X4 K9 f' o$ q8 ]; j
                    distances[v] = distances[u] + weight
0 I8 {  z9 z/ g* }6 }. j/ I, a# I+ v& s
    # 检查负权回路- W+ I  E( r! I, ?) T) n+ U
    for u in graph:8 g: R6 c! r) `1 h4 [4 N
        for v, weight in graph[u].items():
6 e/ E7 U% ~6 g) l            if distances[u] + weight < distances[v]:  h; j: d3 X. @+ K5 F/ D) P/ [, n
                raise ValueError("Graph contains a negative weight cycle")
* ?; B8 k( R; z. t' w5 x# O& k
    return distances* e; H$ f5 B' j" h0 N% x

! X' u4 F; k2 L2 Z$ \1 M7 T4 p# 示例图(带有负权边)
/ a4 |& }' B- C3 U% Ygraph_with_negative_weight = {
" p* _; H+ T" ?8 {    'A': {'B': 1, 'C': 4},2 a( W& q* o2 p$ D; f* B. Y
    'B': {'C': -3, 'D': 2},. s1 G0 G& M8 b* |- F
    'C': {},# L8 X; ?( J1 k! J* T$ D
    'D': {'A': -1}
" c! T7 ~% V3 i% K}
9 Y8 U& _' h5 ^- u6 C: T% q- a! V! {1 L! g! i; A0 @. ]3 \
start_node = 'A'
0 v9 G( ?( T% u+ \shortest_paths = bellman_ford(graph_with_negative_weight, start_node)
& y/ T( f9 U+ f. ]% z; Yprint(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}  X* n6 [% \. m) }( {; u# g' V
```
  x1 h8 O$ N7 N3 i7 i
3 }4 g8 D$ Y0 z% |## 3. Floyd-Warshall 算法
9 G0 N4 q$ C8 d% g0 D2 x! N& d# t0 x6 L0 q# T
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
- b4 ~  j  u9 U  `! E. h$ |5 }, Z2 z3 l; m
### 原理步骤
$ q! }- [8 ]1 F8 M; p  w9 g# A" K, R4 W0 ^
1. **初始化**:
1 J$ R% ^( v! z. P1 e+ M0 h  {* \% y   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。3 W8 T1 I" I$ ]6 T# v3 m% W6 j
; a& {: H$ ?# S0 ]) o
2. **更新路径**:
' q( A& Q& L0 M( i- t7 ~1 F   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。1 x( ^! I- a  C9 Y' y

: Y" Q$ j$ ?" O  E3. **输出结果**:
9 A9 R0 W8 R. @% |* Z   - 最终得到的矩阵即为每对节点之间的最短路径长度。7 \+ b0 y3 v8 {# E3 j
/ }6 {% h& Q& D6 `( Y
### 示例代码
9 Q% g$ P- K  @) ~6 }: \: P5 A3 S( [6 K$ |$ n
```python
* g  c2 I" D5 h7 u% g% t  [" mdef floyd_warshall(graph):' o% x% i. P" z3 E5 x
    # 初始化距离矩阵3 E  z( ?$ i" `. {1 q6 y( Y0 g
    nodes = list(graph.keys()). U' g; w& @& p# V+ f5 ?. F
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}
. \7 y0 {  `: |% S* b' d$ {* |- j; C# F  A1 }, a; a
    for u in nodes:8 s" K9 \/ ^# `) H4 z3 s" Z5 Q
        distances[u][u] = 0
& U+ Q& _7 x% @. f2 k        for v, weight in graph[u].items():
' S1 F6 ~$ l, O& V7 _            distances[u][v] = weight
7 c' s2 d5 J7 g6 V/ U2 n
! T! }  \+ ]8 R$ g1 T* ]; `' f! @    # 更新路径
! z! w8 z% H& z- P  z* I3 ~    for k in nodes:
* k' B$ ]% J. j0 D1 L0 B0 v$ @7 q        for i in nodes:( i: E! ~9 T9 \5 p$ G7 q
            for j in nodes:
; E% ]# J6 f2 J6 ^2 E7 i# Y$ u: H                if distances[i][j] > distances[i][k] + distances[k][j]:
% |6 |( |2 U' E4 E- c. \: t                    distances[i][j] = distances[i][k] + distances[k][j]! `) ?8 c! h. P0 i) ]/ _* {8 L
5 `2 d7 l& k# W0 C# K' M
    return distances6 P& X7 ^' J# H; R& m; _% E6 r6 f7 B- N

- ?& u/ S& M& w7 y8 s# 示例图(可以含负权边)- ~- Z' V( K# V: y2 J. g! \4 f* S
graph_for_floyd = {
- O- {, u2 o! ?7 t    'A': {'B': 3, 'C': 8, 'D': -4},- a6 q9 R: V$ S) n1 F
    'B': {'C': 1, 'D': 7},. |: P; h+ I/ T8 y% Z. H5 h5 h
    'C': {'B': 4},
  j' x; o; {- E    'D': {'A': 2, 'C': -5}1 U5 B- \: N9 `1 |" V  {. {( @0 G' o
}
& ], K, g. [1 |+ h
; [! l, J$ w9 n9 r4 D& wshortest_paths_matrix = floyd_warshall(graph_for_floyd)
. f" U1 Q1 u- Ifor row in shortest_paths_matrix.items():
* v* J! X4 g$ v" d7 q    print(row)* [4 k! V. L4 c& S6 x4 {- n( d# u
```9 U6 N4 u: K0 Y* e
: T) l: B# b2 t0 I7 W; N
## 总结1 V/ k$ x( [- F; Y8 T) j
4 w, R- r- `* B- `# u
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
- h5 t5 }! E1 z2 }- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
( M% N, w- L0 D3 `* j+ q0 `. W- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。
- E" s8 P+ Z3 D& h- J; J; G' a6 C% F1 @; w3 u, t/ A5 s
不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!
1 D9 K5 ]' o& r) m8 c. p! h* m/ s* P! |. f4 \7 R
4 z8 ]: C! A+ B

7 q+ ^; n, o  F! m  }9 `$ 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-10-14 09:09 , Processed in 2.827006 second(s), 55 queries .

回顶部