求最短路径的三种算法: Ford, Dijkstra和Floyd
Bellman-Ford算法
Bellman-Ford是一种容易理解的单源最短路径算法, Bellman-Ford算法需要两个数组进行辅助:
dis[i]: 存储顶点i到源点已知最短路径path[i]: 存储顶点i到源点已知最短路径上, i的前一个顶点.
若图有n个顶点, 则图中最长简单路径长度不超过n-1, 因此Ford算法进行n-1次迭代确保获得最短路径.
Ford算法的每次迭代遍历所有边, 并对边进行松弛(relax)操作. 对边e进行松弛是指: 若从源点通过e.start到达e.stop的路径长小于已知最短路径, 则更新已知最短路径.
为了便于描述, 本文采用python实现算法. 首先实现两个工具函数:
INF = 1e6
def make_mat(m, n, fill=None):
mat = []
for i in range(m):
mat.append([fill] * n)
return mat
def get_edges(graph):
n = len(graph)
edges = []
for i in range(n):
for j in range(n):
if graph[i][j] != 0:
edges.append((i, j, graph[i][j]))
return edges
make_mat用于初始化二维数组, get_edges用于将图由邻接矩阵表示变换为边的列表.
接下来就可以实现Bellman-Ford算法了:
def ford(graph, v0):
n = len(graph)
edges = get_edges(graph)
dis = [INF] * n
dis[v0] = 0
path = [0] * n
for k in range(n-1):
for edge in edges:
# relax
if dis[edge[0]] + edge[2] < dis[edge[1]]:
dis[edge[1]] = dis[edge[0]] + edge[2]
path[edge[1]] = edge[0]
return dis, path
初始化后执行迭代和松弛操作, 非常简单.
由path[i]获得最短路径的前驱顶点, 逐次迭代得到从顶点i到源点的最短路径. 倒序即可得源点到i的最短路径.
def show(path, start, stop):
i = stop
tmp = [stop]
while i != start:
i = path[i]
tmp.append(i)
return list(reversed(tmp))
Ford算法允许路径的权值为负, 但是若路径中存在总权值为负的环的话, 每次经过该环最短路径长就会减少. 因此, 图中的部分点不存在最短路径(最短路径长为负无穷).
若路径中不存在负环, 则进行n-1次迭代后不存在可以进行松弛的边. 因此再遍历一次边, 若存在可松弛的边说明图中存在负环.
这样改进得到可以检测负环的Ford算法:
def ford(graph, v0):
n = len(graph)
edges = get_edges(graph)
dis = [INF] * n
dis[v0] = 0
path = [0] * n
for k in range(n-1):
for edge in edges:
# relax
if dis[edge[0]] + edge[2] < dis[edge[1]]:
dis[edge[1]] = dis[edge[0]] + edge[2]
path[edge[1]] = edge[0]
# check negative loop
flag = False
for edge in edges:
# try to relax
if dis[edge[0]] + edge[2] < dis[edge[1]]:
flag = True
break
if flag:
return False
return dis, path
Dijkstra算法
Dijkstra算法是一种贪心算法, 但可以保证求得全局最优解. Dijkstra算法需要和Ford算法同样的两个辅助数组:
dis[i]: 存储顶点i到源点已知最短路径path[i]: 存储顶点i到源点已知最短路径上, i的前一个顶点.
Dijkstra算法的核心仍然是松弛操作, 但是选择松弛的边的方法不同. Dijkstra算法使用一个小顶堆存储所有未被访问过的边, 然后每次选择其中最小的进行松弛.
def dijkstra(graph, v0):
n = len(graph)
dis = [INF] * n
dis[v0] = 0
path = [0] * n
unvisited = get_edges(graph)
heapq.heapify(unvisited)
while len(unvisited):
u = heapq.heappop(unvisited)[1]
for v in range(len(graph[u])):
w = graph[u][v]
if dis[u] + w < dis[v]:
dis[v] = dis[u] + w
path[v] = u
return dis, path
Floyd
floyd算法是采用动态规划思想的多源最短路径算法. 它同样需要两个辅助数组, 但作为多源最短路径算法, 其结构不同:
dis[i][j]: 保存从顶点i到顶点j的已知最短路径, 初始化为直接连接path[i][j]: 保存从顶点i到顶点j的已知最短路径上下一个顶点, 初始化为j
def floyd(graph):
# init
m = len(graph)
dis = make_mat(m, m, fill=0)
path = make_mat(m, m, fill=0)
for i in range(m):
for j in range(m):
dis[i][j] = graph[i][j]
path[i][j] = j
for k in range(m):
for i in range(m):
for j in range(m):
# relax
if dis[i][k] + dis[k][j] < dis[i][j]:
dis[i][j] = dis[i][k] + dis[k][j]
path[i][j] = path[i][k]
return dis, path
算法核心是遍历顶点k, i, j. 若从顶点i经过顶点k到达顶点j的路径, 比已知从i到j的最短路径短, 则更新已知最短路径.
求最短路径的三种算法: Ford, Dijkstra和Floyd的更多相关文章
- 【2018寒假集训Day 7】【最短路径】三种算法的模板
Luogu单源最短路径模版题 dijkstra #include<cstdio> #include<vector> using namespace std; const int ...
- c语言求回文数的三种算法的描述
c语言求回文数的三种算法的描述 题目描述 注意:(这些回文数都没有前导0) 1位的回文数有0,1,2,3,4,5,6,7,8,9 共10个: 2位的回文数有11,22,33,44,55,66,77,8 ...
- (最短路径算法整理)dijkstra、floyd、bellman-ford、spfa算法模板的整理与介绍
这一篇博客以一些OJ上的题目为载体.整理一下最短路径算法.会陆续的更新... 一.多源最短路算法--floyd算法 floyd算法主要用于求随意两点间的最短路径.也成最短最短路径问题. 核心代码: / ...
- 最短路问题的三种算法&模板
最短路算法&模板 最短路问题是图论的基础问题.本篇随笔就图论中最短路问题进行剖析,讲解常用的三种最短路算法:Floyd算法.Dijkstra算法及SPFA算法,并给出三种算法的模板.流畅阅读本 ...
- 算法学习笔记(三) 最短路 Dijkstra 和 Floyd 算法
图论中一个经典问题就是求最短路.最为基础和最为经典的算法莫过于 Dijkstra 和 Floyd 算法,一个是贪心算法,一个是动态规划.这也是算法中的两大经典代表.用一个简单图在纸上一步一步演算,也是 ...
- Java利用DES/3DES/AES这三种算法分别实现对称加密
转载地址:http://blog.csdn.net/smartbetter/article/details/54017759 有两句话是这么说的: 1)算法和数据结构就是编程的一个重要部分,你若失掉了 ...
- 内存分配---FF、BF、WF三种算法
动态分区分配是根据进程的实际需要,动态的为之分配内存空间.而在实现可变分区分配时,将涉及到分区分配中 所用的数据结构.分区分配算法和分区的分配与内存回收的过程. 分区分配中的数据结构:(1)描述空闲块 ...
- 图文实例解析,InnoDB 存储引擎中行锁的三种算法
前文提到,对于 InnoDB 来说,随时都可以加锁(关于加锁的 SQL 语句这里就不说了,忘记的小伙伴可以翻一下上篇文章),但是并非随时都可以解锁.具体来说,InnoDB 采用的是两阶段锁定协议(tw ...
- 求最短路的三种方法:dijkstra,spfa,floyd
dijkstra是一种单源最短路算法.在没有负权值的图上,vi..vj..vk是vi到vk最短路的话,一定要走vi到vj的最短路.所以每次取出到起点距离最小的点,从该点出发更新邻接的点的距离,如果更新 ...
随机推荐
- 实现EventHandler的监测
的监测", "category":"", "tags":"", "publish":&qu ...
- WebAPI开发中的定时处理
https://blog.csdn.net/lordwish/article/details/77931897
- [.net]数组
在C语言中,数组是比较简单,也使用比较多的一种基础的数据结构.常用的有一维数组,二维数组等.但是在C#中,使用最多的是List,Dictionary等一些集合类,因为用他们来操作同类型的数据,比数组更 ...
- 【大数据之数据仓库】kudu性能测试报告分析
本文由 网易云发布. 这篇博文主要的内容不是分析说明kudu的性能指标情况,而是分析为什么kudu的scan性能会这么龊!当初对外宣传可是加了各种 逆天黑科技的呀:列独立存储.bloom filte ...
- day 23 面向对象的命名空间与组合
创建一个类就会创建一个类的名称空间,用来存储类中定义的所有名字,这些名字称为类的属性 而类有两种属性:静态属性和动态属性 1. 静态属性就是直接在类中定义的变量 2.动态属性就是定义在类中的方法. 其 ...
- python 进程、线程、协程感悟
进程: 感觉只是使用Process模块加以使用即可: # -*- coding: utf-8 -*- # data:2019-02-23 21:23 # user:DIY # file:thread_ ...
- Django 使用getattr() 方法获取配置文件的变量值
在django项目的开发过程中,有时需要获取配置文件里的变量值,可以通过下面这样的方式去进行获取 from django.conf import settings item = getattr(set ...
- Python面向对象(特殊成员)
day25 __init__ 类()自动执行 __del__ __call__ 对象() 类()() 自动执行 __int__ int(对象) ...
- Ceres入门笔记
介绍 Ceres可以解决下列形式的边界约束鲁棒非线性最小二乘问题 (1) $\min\limits_{x}\quad \frac{1}{2} \sum\limits_{i}\rho_{i}\left( ...
- [bug]微信小程序使用 <scroll-view> 和 box-shadow 引起页面抖动
背景 为了实现点点点动态loading效果,并且方便使用(只需要给一个空元素加一个.loading),有如下代码: .loader { background-color: #fff; font-siz ...