QQ登录

只需要一步,快速开始

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

最短路径算法Python代码

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

1188

主题

4

听众

2931

积分

该用户从未签到

跳转到指定楼层
1#
发表于 2025-1-13 17:26 |只看该作者 |倒序浏览
|招呼Ta 关注Ta
最短路径算法用于寻找图中两点之间的最短路径。这类算法在网络路由、地图导航、物流和许多其他应用中起到关键作用。常见的最短路径算法包括 Dijkstra 算法、Bellman-Ford 算法和 Floyd-Warshall 算法。下面将介绍这些算法的基本原理和具体实现。
7 `, i& p3 I. e! t; F; p4 l" c1 L; G( {2 s: W/ A
## 1. Dijkstra 算法
& I& Q. v7 ]" ]2 L; d& k) ]
; E& o8 h1 f6 \Dijkstra 算法用于计算单源最短路径,有效于边权为非负数的图。它通过贪心策略逐步选择最短路径,从起点出发扩展到其他节点。, ^3 D5 G; z4 R3 \1 \
! G+ o% s9 f% a7 `0 C
### 原理步骤/ @! m. a: z/ k) f! B1 J( U- v

5 y9 o% A! \: s% E& e1. **初始化**:
7 b* r8 a6 k# j* L$ H) l   - 设置源节点到自己的距离为0,其他节点为无穷大(一般用 `inf` 表示)。' r0 B* J! a  L7 T# P6 W' T
   - 初始化一个空的优先队列,用于存储待处理的节点。1 z8 C  {9 K+ ]6 X
; o* z. \/ j$ E% O
2. **处理节点**:
. S8 V4 {# @: G; Y. F8 F   - 从优先队列中选取距离最小的节点作为当前节点。8 k8 Z1 L5 g4 }1 Y3 I) ~
   - 更新当前节点的所有邻接节点的距离。如果新的距离更短,则更新并将邻接节点加入优先队列。( P3 D  j  X: K
1 o% P! b, a% H, g( U1 L% P6 z
3. **重复处理**:- G3 z: m" F2 Y! L) v( d2 {. k* _0 v
   - 继续选择距离最小的节点,直到处理完所有节点或找到目标节点。! b5 h% o# c+ U7 G$ `
8 X( |2 T3 _1 g3 a+ L) t$ J) }
### 示例代码% v, t; N) P  J9 B3 \) K

3 p! v9 j5 X* [```python9 o# r  v' N0 `2 `
import heapq5 a2 l9 X; _+ ?4 O1 e' \, t! d% p

; j' B- ~: ^  l* l! vdef dijkstra(graph, start):, T8 e# i( q. L" ?2 `
    # 图的表示为字典,键为节点,值为邻接节点及其边权
/ s. R9 p7 w  [    queue = []$ p9 u: y3 K' [4 ~) D
    distances = {node: float('inf') for node in graph}! G) ^. Y' q( s; A8 j/ m
    distances[start] = 0% O! s  B) U0 G( n6 E
    heapq.heappush(queue, (0, start))  # (距离, 节点)
% L6 q  m; z+ d% n/ m7 X, p4 S
# G: |; v; M$ ]6 V    while queue:: N: a8 r* t0 a  j  k
        current_distance, current_node = heapq.heappop(queue)9 p: s% o( f7 |! D6 I) x& y: z
5 ^. K& p$ h2 \( N1 h9 T
        # 只处理当前节点的最短距离# \+ w# t2 u5 E+ F" A
        if current_distance > distances[current_node]:
. B9 ^/ Y0 ?2 C) ]) U( e+ b            continue
6 w. J' b; ?# j! U3 V/ o
, Z  _$ v% |# l+ h# Y& r  I6 Y8 g2 P        for neighbor, weight in graph[current_node].items():
+ ~/ E" D2 ^4 q/ W2 F6 \; U# M            distance = current_distance + weight/ k! m8 j  Z# Q2 i  [; r* ^% b

: \# S7 D0 h0 P* i! a: N- f            # 更新邻接节点的距离
8 N# A: M1 H1 Q( a$ l5 c            if distance < distances[neighbor]:
5 I8 x0 s! i5 X/ ~3 E" [                distances[neighbor] = distance
, i5 e* W5 J# c% _6 h                heapq.heappush(queue, (distance, neighbor))& f2 S0 o: ]! _& \  w( e: ]3 k/ A/ N# Q
- `% J2 F/ ?' g
    return distances
' O* i1 z( a) R, Q" \
8 ?4 `) [9 w. P# 示例图0 X9 E. h/ R9 I
graph = {
/ B0 k1 `8 M1 c! p8 ]5 R" x% v    'A': {'B': 1, 'C': 4},# m+ v0 ^% [/ }# P' j3 ?
    'B': {'A': 1, 'C': 2, 'D': 5},& f" a) Y5 l  p6 d
    'C': {'A': 4, 'B': 2, 'D': 1},
% O3 P+ c( q" B, v+ D6 S7 z: g5 A0 c    'D': {'B': 5, 'C': 1},
+ ^% {- b4 f& v+ ]2 a) r! X}' c: }9 B* d8 d
- }1 [# J+ T: b+ u
start_node = 'A'
* W4 B9 G7 O( n& N) D8 C) ]shortest_paths = dijkstra(graph, start_node)* t/ @, I- I0 m6 f
print(shortest_paths)  # {'A': 0, 'B': 1, 'C': 3, 'D': 4}/ S# J2 g8 j) @8 V) L; B
```7 ~1 L6 t- i4 }9 d% {
! W: G/ e8 i5 }% E' H
## 2. Bellman-Ford 算法
: W4 f' e9 f. I( e: C1 d  g* b2 g- c+ b' w5 A
Bellman-Ford 算法能够处理带有负权边的图,但不能处理负权回路。它通过放松操作逐步更新从源节点到所有其他节点的最短路径。  D- E2 ?1 I% C6 E( T2 N3 c1 p5 U# ]

0 [+ {; B  T' X3 z5 e1 f) d' p### 原理步骤
; s6 b9 ]1 C6 m( X5 ?6 e" Q6 b- y  m9 a$ P/ ^( \0 M. A
1. **初始化**:6 S( H9 ^5 V3 R
   - 设置源节点到自己的距离为0,其他节点为无穷大。
; h- v" S9 V! N$ l
5 J" g  a' N6 R4 C" ]5 P2. **松弛操作**:7 n5 F  X* W4 ^9 T
   - 对所有边进行松弛操作,循环(V-1)次(V为节点数),尝试更新每个边的距离。1 x) p: l6 t% {4 l

( H9 K) A4 z# W3 ~4 |( q3. **检查负权回路**:5 H& l9 G, C& |2 b
   - 再次对所有边进行一次松弛检查,如果有边的距离仍能被更新,则说明图中存在负权回路。; F& q) _# ?0 X+ P
5 k( T0 v% _9 k1 h4 m5 r7 t
### 示例代码1 ?" _0 o# o5 X, k1 h

, T) R4 L* o5 G  m( }% X```python
. P* V: l: A/ h2 wdef bellman_ford(graph, start):
/ d  A) @. v8 ^6 }0 b# I" U' S    # 初始化距离$ l0 @& [( ]/ k! b
    distances = {node: float('inf') for node in graph}, \/ S( d/ c; q0 @8 `" F
    distances[start] = 0
7 J) [/ G8 o8 R8 P$ R0 m! X
; c# s7 i9 v/ |2 w7 [    # 松弛操作# S8 r% C+ s) u1 a% `; _
    for _ in range(len(graph) - 1):1 i5 n, l( H$ ^8 X
        for u in graph:
5 c2 u: W3 N! H+ W1 S. M$ v            for v, weight in graph[u].items():
% D, A# N5 {8 Y. S% P, q% z                if distances[u] + weight < distances[v]:
3 J( \4 o! I( k5 K& K& a% X& w                    distances[v] = distances[u] + weight
+ ~; j: p) S5 `8 G/ M6 r9 |* n- ^, m/ N9 H- n) b# a6 L' U8 G
    # 检查负权回路% i% ~1 A8 w" b. F
    for u in graph:  |% _1 i5 ?) r& i$ _
        for v, weight in graph[u].items():
6 r$ R$ U$ p( R2 x0 P            if distances[u] + weight < distances[v]:
$ O& H: @, P, J  @  D" N                raise ValueError("Graph contains a negative weight cycle")
* ^5 `( m" A% l3 W( T. }: J6 ~- Y, s- d/ k) _+ _$ G# u
    return distances1 e3 ^, t  ]: _/ ^  l7 l1 e  b+ w

* h1 a0 [/ m6 R7 h# 示例图(带有负权边), \- ]$ a! h7 r  R# F. i; v
graph_with_negative_weight = {6 K" O! M% Z* `( o! o
    'A': {'B': 1, 'C': 4},
- ^- w% b2 V$ a  }/ I9 Z    'B': {'C': -3, 'D': 2},
, X& N  k& N  c+ o. }& \' u    'C': {},
6 f' L, `. v9 Z& U2 E  S    'D': {'A': -1}3 n: q$ @. U- P$ m! _9 N
}9 }5 h  q8 X3 w  C5 y

2 ~, M' g; L0 ]+ O" hstart_node = 'A'2 t9 t8 q: q) u1 O8 ~
shortest_paths = bellman_ford(graph_with_negative_weight, start_node)
- O- W6 B% d9 D; \6 c  @print(shortest_paths)  # {'A': 0, 'B': 1, 'C': -2, 'D': 3}
* f1 u! [& p; }```
+ ?( f# f3 {6 w' j- s; ~* ?( ]
## 3. Floyd-Warshall 算法
7 K; E' h$ R. f0 b6 K! B  E7 Y, g' ^' `7 e" c; r, ~* h6 O) k* D  u
Floyd-Warshall 算法用于寻找图中所有节点之间的最短路径,适用于边权任意的图,包括有负权边但无负权回路的情况。
# p. X9 ]' W& n( N2 ~5 T- _; k9 K* r  w" ?$ d# i
### 原理步骤
" i( ?  Z2 [$ S$ p. d! k0 R- z/ B! j; h! c+ W6 T; Y  p; O, I. C( b
1. **初始化**:3 g; ^8 Y; O6 H3 I& K, ~
   - 创建一个距离矩阵,初始化为无穷大,源节点到自身的距离置为0,直接相连的节点的距离为边权。
9 ?7 W# \0 D+ [2 O5 B7 b; f( f0 h) V
2. **更新路径**:+ G; X# e4 N! J3 t  @# G
   - 三重循环遍历所有节点,以每个中间节点尝试更新路径。! r; O6 ^, u$ E
4 J4 \6 b6 X) S. Z( J
3. **输出结果**:
. O$ P, B' M) R3 O$ A   - 最终得到的矩阵即为每对节点之间的最短路径长度。' H- G& h7 X/ ^2 W4 ]! L

- m; _9 x7 U. T/ H. u, }: ^### 示例代码/ H1 c/ |* }0 A$ }# c( z, f4 |, H

0 W  ]$ {0 U: l9 Q2 E```python( ]$ `' n; I. T# ~1 k
def floyd_warshall(graph):% o* o; d, o9 w  E9 ?% y9 K3 D
    # 初始化距离矩阵# s; [3 L, B- }& A: A
    nodes = list(graph.keys())( z$ n7 h4 l4 X9 P6 R3 c
    distances = {node: {n: float('inf') for n in nodes} for node in nodes}0 |% Q% X2 M! u7 Y# A) b
7 \" c+ ~5 Z; m- S* e% S  E
    for u in nodes:7 ~* @( o7 d; [- ?" U
        distances[u][u] = 0/ _/ H& W* @) I" D. i! Z
        for v, weight in graph[u].items():
" K  O6 E( `+ |; U2 F            distances[u][v] = weight
) J: U; G* a% h. m6 V% E0 d9 E' g/ d% x! S
    # 更新路径
7 I9 m$ d$ r1 k9 o3 ]    for k in nodes:
+ u7 b& W$ Q1 J# a/ K3 q7 `5 U        for i in nodes:
+ W% G6 J$ P+ ~+ J" T            for j in nodes:
0 ^8 V- L( P; M& W7 I                if distances[i][j] > distances[i][k] + distances[k][j]:
. ?/ I5 s- t3 s0 J5 S                    distances[i][j] = distances[i][k] + distances[k][j]( l6 C6 k* y8 u- w

7 o# X) s, D8 ^% J. J    return distances
7 g3 W! ]5 t9 _; V, h$ W; t, Q8 p+ W, Q, i+ G2 V* q
# 示例图(可以含负权边)
1 ]$ [) o& x1 q8 h+ ~# ]graph_for_floyd = {3 B: ^( H; H: P+ l
    'A': {'B': 3, 'C': 8, 'D': -4},) k- ?0 r$ Q" c' }  Q5 p
    'B': {'C': 1, 'D': 7},
7 C+ q0 J6 g. j* T    'C': {'B': 4},
7 F+ m  C* }2 _  o: R4 e    'D': {'A': 2, 'C': -5}
: z, t2 a& R; d1 [- |" a0 ?% f" k}6 T" ~: T$ @6 H, b8 Y* B$ T( g6 S# Z

' A5 G* m$ R* A' Y. A% l% qshortest_paths_matrix = floyd_warshall(graph_for_floyd)
% H/ A$ c% D$ @9 U8 s2 e' Wfor row in shortest_paths_matrix.items():6 p& K5 e. o' j  q. ], z
    print(row)
0 Z- b: l" |4 Y, m& p```1 j* z  T: U: q$ W0 O( D+ R
: K) t+ H9 E7 S
## 总结& q( O* V( D& r" \. D
- a" t" m, E9 t  m! v+ a
- **Dijkstra 算法**适合用于无负权边图,时间复杂度为 \(O((V + E) \log V)\),其中 \(V\) 为节点数,\(E\) 为边数。
% C- ]. ?6 I5 J: C( M' b- **Bellman-Ford 算法**适合处理含负权边的图,时间复杂度为 \(O(VE)\)。
- P9 E) ^* g7 t) S- **Floyd-Warshall 算法**用于所有节点对最短路径计算,时间复杂度为 \(O(V^3)\)。& w, Y* E6 A" U

0 g  @* m  _5 S  e& C不同算法适用于不同的问题场景,选择适合的算法是解决最短路径问题的关键。如果需要更详细的介绍或有特定问题,欢迎进一步询问!  X/ J1 \" G4 Q6 V8 R' a' s" k; v

1 F/ d7 O! A+ f1 n( \* |& J. ]9 T( a( q/ M! K& w7 [! b/ W
1 X0 q, V" \/ @0 S& B3 ?/ k( e$ _' E

最短路径算法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 10:59 , Processed in 0.300480 second(s), 55 queries .

回顶部