图论-单源最短路径算法(拓扑,Dijkstra,Floyd,SPFA)
前言
单源最短路径是学习图论算法的入门级台阶,但刚开始看的时候就蒙了,什么有环没环,有负权没负权,下面就来总结一下求单源最短路径的所有算法以及其适用的情况。
单源最短路径
设定图中一个点为源点,求其他所有点到源点的最短路径。
先声明一点:有负环的图中没有最短路径
因为负环绕一圈的权值和是负的,只要过一遍环,路径就减小,可以反复过,无限减小
1. 无环 无负权 图求单源最短路径--拓扑排序
求v到其他所有点的最短路径
归纳假设
已知v到前面n-1个点的最短路径
求n
假设每一个点带一个属性sp,表示该点到源点的最短路径长度
设第n个点为z
我们知道所有能到z的点wk,即(wk, z)是图中的边
这样求出来wk.sp + len(wk, z)的最小值
就是z的sp
为什么要拓扑排序?
拓扑排序保证看n的时候,与n连接的前面的所有点都看了
复杂度O(V + E)
伪代码:
const int MAX = MAX_INT
for(all w){w.sp = MAX}init w.indegree DFSw with 0 indegree, enqueuewhile(!queue.empty()){w = dequeue();for(all (w, z)){if(w.sp + len(w, z) < z.sp){z.sp = w.sp + len(w, z);}z.indegree--;if(z.indegree = 0){z.enqueue();}}}
2. 有环 无负权 图求单源最短路径--Dijkstra算法
前面拓扑排序的求所有点的最短路径只能是无环图
有环会导致拓扑排序无法终止
没法用
Dijkstra算法可以解决有环 无负权最短路径的问题
Dijkstra算法是求源点到其他所有点的最短路径
定义两个集合
一个集合是S, 表示已经确定了最短路径的点
另一堆是剩下的所有点M的集合
Init-每个点的路径长度设为无穷
每次从剩下的点中取路径长度最小的加入到S中
开始
只有源点在S中
计算源点所有连接点的路径长度
取出最小x的加入到S中
并对所有连接x的点更新路径长度
再挑出最小的
反复
直到所有点都加到S中
解决了
注意:这里与prim算法有点像
Diljstra算法是不断从剩下的点中选取路径最小的加入的S中
prim算法是不断从剩下的点中选取能到S且边的权值最小的加入到S中
伪代码:
const int MAX = MAX_INT;
for(all w except v in G){w.sp = MAX;w.mark = false;}v.sp = 0;build a heap for all vetex;while(there exist unmarked vertex){w = heap.pop(); //w.sp is minimumw.mark = true;for(all (w, z) in G and z is unmarked){if(w.sp + len(w, z) < z.sp){z.sp = w.sp + len(w, z);}}heapsort();}
build the Heap // O(VlogV)
最多需要E次更新,每一次更新O(logv)
从而总时间
O((E+V)logV)
问:为什么Dijkstra算法不能求解带负权的路径的图的最短路径?
答:采用dijkstra算法处理带有负权边的图时有可能出现这样一种情况:因为dijktra算法每一次将一个节点加入已访问集合之中,之后不能在更新,
如图
算法刚开始执行时,将A添加到集合中标记已访问,之后选出从A到所有节点中的最短的d,于是把C加入集合中标记已访问,之后C不能在更新了,而显然,A与C之间最短路径权值为0(A-B-C),发生错误。
3. 有环 有负权 图的单源最短路径--Floyd算法
可以用于带负权的图
Floyd算法
动态规划
C[i][j] 表示i点到j点的最短距离
小问题可解-所有相邻的边的权值已知
大问题分解为小问题
从i到j
两种途径
1.图中有边连接i与j
2.经过k点到,C[i][j] = C[i][k] + C[k][j]
1 <= k <= N
两种的最小值就是C[i][j]
定义矩阵C[N][N]
然后不断dp
伪代码:
const int MAX = MAX_INT;c[N][N]for(i = 1; i <= N; i++){for(j = 0; i <= N; j++){if((i, j) is in G ){c[i][j] = (i, j).weight;}else{c[i][j] = MAX;}}}for(k = 1; k <= N; j++){for(i = 1; i <= N; i++){for(j = 0; j <= N; j++){if(c[i][j] > c[i][k] + c[k][j]){c[i][j] = c[i][k] + c[k][j];}}}}
复杂度O(n^3)
注意k只能放在最外层的循环
不能放在最里层
若放在最里层
计算第一行eg (1, 10)时
要算(1, 5) (5, 10)
但这时(5, 10)还未知
所以确定的(1, 10)点的最短路径是不准确 的
k放最外面的循环中
保证计算每次看计算C[i][j]时, C[i][k] + C[k][j]都是已经求过的值
4. 有环 有负权 图单源最短路径算法--SPFA
带有负权的图
不能使用Dijkstra算法
floyd算法又复杂度太高
然后西安交通大学acm大牛想出了SPFA
中华少年英才多啊
SPFA
设立一个队列
d[i]表示源点到i的最短距离
init所有d[i]都为无穷
刚开始源点入队
x出队
检查x连接的所有点d[i]值,如果变小,则跟新
更新了的点y,说明与y连接的点也有可能更新
y入队
之后不断反复
因为点数有限,所以必然一定步骤后队列会为空
这时就求得了所有点的最短路径
真TMD神奇
检查每个点连接的所有点,总检查就是边数E
每个点可能入队多次,设平均入队次数为k
复杂度O(kE)
可以证明k<=2
Spfa 有两种实现方法:bfs,dfs
bfs判断起来较麻烦
得计算所有点入队的次数
如果一个点入队超过N次,一定有负环
bfs伪代码:
const int MAX = MAX_INTspfa_bfs(){suppose root = s;d[N]; //The min path length of s to ivis[N]; //1 -- i is in the queuecount[N]; //The count of i to enqueuefor(i = 1; i <= N; i++){d[N] = MAX;}d[s] = 0;vis[s] = 1;count[s] = 1;enqueue(s);while(!queue.empty()){x = dequeue();vis[s] = 0;for((x, y) is in G){if(d[y] > d[x] + len(x, y)){d[y] = d[x] + len(x, y);vis[y] = 1;count[y]++;if(count[y] >= N){return -1; // There is a minus circle}}}}}
dfs 伪代码:
判断负环较快
vis[N]; //1 -- i is checkedint spfa_dfs(point v){vis[v] = 1;for((v, w) is in G){if(d[w] > d[v] + len(v, w)){d[w] = d[v] + len(v, w);if(vis[w] == 0){if(spfa_dfs(w) == -1){return -1;} //-1 there is a minus circle}else{return -1;}}}vis[v] = 0;}
总结
无环 无负权 图单源最短路径--拓扑排序
有环 无负权 图单源最短路径--Dijkstra算法
有环 有负权 图单源最短路径--Floyd算法
有环 有负权 图单源最短路径--SPFA
这里总结了计算单源最短路径的四种常见算法,理清楚他们分别适用的情况,以及他们之间的关系便会很好记忆。
图论-单源最短路径算法(拓扑,Dijkstra,Floyd,SPFA)相关推荐
- 用java编写的一个迪杰斯特拉算法(单源最短路径算法,Dijkstra算法)。
可以用于有向图和无向图.用负数表示该有向路不通.在EditPlus上写的,所以就一个.java文件. package Test;import java.util.TreeMap; import jav ...
- Dijkstra 单源最短路径算法 Java实现
Dijkstra 单源最短路径算法 Java实现 算法导入 算法核心 复杂度分析 时间复杂度 空间复杂度 代码实现 参考资料 结尾 算法导入 在图论中,求最短路径有一个经典的算法 Dijkstra算法 ...
- C++实现dijkstra单源最短路径算法-邻接表+优先队列
dijkstra单源最短路径算法不允许边权值为负,适用的图范围可以很大. 代码如下: #include <iostream> #include <queue> #include ...
- Dijkstra单源最短路径算法
这里写目录标题 一.算法原理 二.MATLAB实现 三.参考文献 一.算法原理 迪杰斯特拉算法(Dijkstra)是由荷兰计算机科学家狄克斯特拉于1959 年提出的,因此又叫狄克斯特拉算法.是从一个顶 ...
- 单源路径分支界限java_java单源最短路径算法
. .. .. . 单源最短路径的 Dijkstra 算法: 问题描述: 给定一... 并 应用贪心法求解单源最短路径问题.环境要求对于环境没有特别要求.对于算法实现,可以自由选择 C, C++, J ...
- Python单源最短路径算法汇总
给定一个带权有向图G=(V,E),其中每条边的权是一个实数.另外,还给定V中的一个顶点,称为源.要计算从源到其他所有各顶点的最短路径长度.这里的长度就是指路上各边权之和.这个问题通常称为单源最短路径问 ...
- Bellman-Ford 单源最短路径算法
Bellman-Ford 单源最短路径算法 Bellman-Ford 算法是一种用于计算带权有向图中单源最短路径(SSSP:Single-Source Shortest Path)的算法.该算法由 R ...
- 四种不同单源最短路径算法性能比较
四种不同单源最短路径算法性能比较 一.最短路径问题描述 单源最短路径描述:给定带权有向图G=(V,E),其中每条边的权是非负实数.另外,还给定V中的一个顶点,称之为源.现在要计算从源到其他各顶点的 ...
- 应用单源最短路径算法解决套利交易问题
目录 导言 基本定义与延伸 基本概念与定义 概念延伸 最短路径算法 Bellman-Ford算法 问题简述 问题分析 问题求解 第一题 第二题 总结 导言 最短路径问题是图论领域中的核心问题之一,也是 ...
最新文章
- 应用开发也去中心化?基于BCH的筹款平台Akari-Pages与Lighthouse正面交锋
- dede 两种幻灯代码
- PHPStorm使用指南
- 电脑温度检测软件哪个好_实时检测Mac电脑的温度
- python3线程gil_python3爬虫GIL修改多线程实例讲解
- CSS的预编译——less语言基本语法教程(入门)
- 使用abcpdf将html转换成pdf文件
- jQuery 查找元素节点
- 8086汇编复习2 - 使用emu8086
- 会员运营是什么?会员运营体系有哪些类别?
- Python开发款短链生成器,来满足我的需求!
- UserData使用总结[转载-lanyu]
- 云原生数据湖以存储、计算、数据管理等能力通过信通院评测认证
- 2021.07.28
- Java教程:使用POI读取excel文档(根据BV1bJ411G7Aw整理)
- 一个javaweb基础的小游戏。。俄罗斯方块。。。
- html跳动的心,css3跳动的心制作
- 2022年企业CS1升级到CS2需要什么条件 ?有什么流程?
- 多版本node安装相关知识
- JVM(四)_性能监控与调优
热门文章
- linux ps 被替换文件怎么恢复,被覆盖的文件如何恢复_被替换掉的文件怎么恢复-win7之家...
- 阿里云easy-excel的使用(springboot整合)
- 斗破苍穹java_安卓斗破苍穹游戏源码
- python中break和continue区别_Python break和continue用法及区别
- codeforces 628.div2
- 如何让table边框变为单实线?
- 网络编程基础 --> 网络通信机理、报文与协议、套接字通信预备
- python pdf 转换成txt,csv,doc 及doc转换为pdf初级
- C2977 “boost::type_of::encode_type”: 模板 参数太多
- Topcoder 2016 TCO Algorithm Algo Semifinal 1 Hard ColorfunPath [网络流]