算法笔记_071:SPFA算法简单介绍(Java)
目录
1 问题描述
何为spfa(Shortest Path Faster Algorithm)算法?
spfa算法功能:给定一个加权连通图,选取一个顶点,称为起点,求取起点到其它所有顶点之间的最短距离,其显著特点是可以求含负权图的单源最短路径,且效率较高。(PS:引用自百度百科:spfa是求单源最短路径的一种算法,它还有一个重要的功能是判负环(在差分约束系统中会得以体现),在Bellman-ford算法的基础上加上一个队列优化,减少了冗余的松弛操作,是一种高效的最短路算法。)
spfa算法思想:spfa就是BellmanFord的一种实现方式,其具体不同在于,对于处理松弛操作时,采用了队列(先进先出方式)操作,从而大大提高了时间复杂度。 (PS:对于BellmanFord算法可以参考本人的另一篇文章算法笔记_070:BellmanFord算法简单介绍(Java))
2 解决方案
2.1 具体编码
spfa算法寻找单源最短路径的时间复杂度为O(m*E)。(其中m为所有顶点进队的平均次数,可以证明m一般小于等于2*图顶点个数,E为给定图的边集合)
首先看下代码中所使用的连通图(PS:改图为无向连通图,所以每两个顶点之间均有两条边):
现在求取上图中顶点B到其它所有顶点之间的最短距离。
具体代码如下(PS:下面代码中对于图的处理是直接遍历所有边,如果把该方法变成使用邻接表来实现,时间效率会更好一点,详见:算法笔记_075:蓝桥杯练习 最短路(Java)中方法2):
- package com.liuzhen.chapter9;
- import java.util.ArrayList;
- import java.util.Scanner;
- public class Spfa {
- public long[] result; //用于得到第s个顶点到其它顶点之间的最短距离
- //内部类,用于存放图的具体边数据
- class edge {
- public int a; //边的起点
- public int b; //边的终点
- public int value; //边的权值
- edge(int a, int b, int value) {
- this.a = a;
- this.b = b;
- this.value = value;
- }
- }
- /*
- * 参数n:给定图的顶点个数
- * 参数s:求取第s个顶点到其它所有顶点之间的最短距离
- * 参数edge:给定图的具体边
- * 函数功能:如果给定图不含负权回路,则可以得到最终结果,如果含有负权回路,则不能得到最终结果
- */
- public boolean getShortestPaths(int n, int s, edge[] A) {
- ArrayList<Integer> list = new ArrayList<Integer>();
- result = new long[n];
- boolean[] used = new boolean[n];
- int[] num = new int[n];
- for(int i = 0;i < n;i++) {
- result[i] = Integer.MAX_VALUE;
- used[i] = false;
- }
- result[s] = 0; //第s个顶点到自身距离为0
- used[s] = true; //表示第s个顶点进入数组队
- num[s] = 1; //表示第s个顶点已被遍历一次
- list.add(s); //第s个顶点入队
- while(list.size() != 0) {
- int a = list.get(0); //获取数组队中第一个元素
- list.remove(0); //删除数组队中第一个元素
- for(int i = 0;i < A.length;i++) {
- //当list数组队的第一个元素等于边A[i]的起点时
- if(a == A[i].a && result[A[i].b] > result[A[i].a] + A[i].value) {
- result[A[i].b] = result[A[i].a] + A[i].value;
- if(!used[A[i].b]) {
- list.add(A[i].b);
- num[A[i].b]++;
- if(num[A[i].b] > n)
- return false;
- used[A[i].b] = true; //表示边A[i]的终点b已进入数组队
- }
- }
- }
- used[a] = false; //顶点a出数组对
- }
- return true;
- }
- public static void main(String[] args) {
- Spfa test = new Spfa();
- Scanner in = new Scanner(System.in);
- System.out.println("请输入一个图的顶点总数n起点下标s和边总数p:");
- int n = in.nextInt();
- int s = in.nextInt();
- int p = in.nextInt();
- edge[] A = new edge[p];
- System.out.println("请输入具体边的数据:");
- for(int i = 0;i < p;i++) {
- int a = in.nextInt();
- int b = in.nextInt();
- int value = in.nextInt();
- A[i] = test.new edge(a, b, value);
- }
- if(test.getShortestPaths(n, s, A)) {
- for(int i = 0;i < test.result.length;i++)
- System.out.print(test.result[i]+" ");
- } else
- System.out.println("给定图存在负环,没有最短距离");
- }
- }
运行结果:
- 请输入一个图的顶点总数n起点下标s和边总数p:
- 6 1 18
- 请输入具体边的数据:
- 0 1 6
- 0 2 3
- 1 2 2
- 1 3 5
- 2 3 3
- 2 4 4
- 3 4 2
- 3 5 3
- 4 5 5
- 1 0 6
- 2 0 3
- 2 1 2
- 3 1 5
- 3 2 3
- 4 2 4
- 4 3 2
- 5 3 3
- 5 4 5
- 5 0 2 5 6 8
参考资料:
1. SPFA算法详解
算法笔记_071:SPFA算法简单介绍(Java)的更多相关文章
- 算法笔记_221:串的简单处理(Java)
目录 1 问题描述 2 解决方案 1 问题描述 串的处理在实际的开发工作中,对字符串的处理是最常见的编程任务.本题目即是要求程序对用户输入的串进行处理.具体规则如下:1. 把每个单词的首字母变为大 ...
- 算法笔记之KMP算法
本文是<算法笔记>KMP算法章节的阅读笔记,文中主要内容来源于<算法笔记>.本文主要介绍了next数组.KMP算法及其应用以及对KMP算法的优化. KMP算法主要用于解决字符串 ...
- (转)简单介绍java Enumeration
简单介绍java Enumeration 分类: java技术备份 java数据结构objectstringclass存储 Enumeration接口 Enumeration接口本身不是一个数据结构 ...
- Bellman-Ford算法的改进---SPFA算法
传送门: Dijkstra Bellman-Ford SPFA Floyd 1.算法思想 Bellman-Ford算法时间复杂度比较高,在于Bellman-Ford需要递推n次,每次递推需要扫描所有的 ...
- 算法笔记_054:Prim算法(Java)
目录 1 问题描述 2 解决方案 2.1 贪心法 1 问题描述 何为Prim算法? 此处引用网友博客中一段介绍(PS:个人感觉网友的这篇博客对于Prim算法讲解的很清楚,本文与之相区别的地方在于具 ...
- 算法笔记_066:Kruskal算法详解(Java)
目录 1 问题描述 2 解决方案 2.1 构造最小生成树示例 2.2 伪码及时间效率分析 2.3 具体编码(最佳时间效率) 1 问题描述 何为Kruskal算法? 该算法功能:求取加权连通图的最小 ...
- JMeter学习笔记2-图形界面简单介绍
废话少说直接干活的给: 一.打开和运行JMeter,出现UI界面.如图下所示: 工具栏:常见操作的图标集合,有New(新建), Template(模板) ,Save(保存),Start(开始) ,St ...
- 算法笔记--lca倍增算法
算法笔记 模板: vector<int>g[N]; vector<int>edge[N]; ][N]; int deep[N]; int h[N]; void dfs(int ...
- 简单介绍 Java 构造器
导读 构造器是编程的强大组件.使用它们来释放 Java 的全部潜力. 在开源.跨平台编程领域,Java 无疑(?)是无可争议的重量级语言.尽管有许多伟大的跨平台框架,但很少有像 Java 那样统一和直 ...
随机推荐
- python之并发编程(线程\进程\协程)
一.进程和线程 1.进程 假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源.是 ...
- Bzoj2818 Gcd(莫比乌斯反演)
题面 题意都在题目里面了 题解 你可以把题意看成这个东西 $$ \sum_{i=1}^n\sum_{j=1}^m\mathbf f(gcd(i,j)) $$ 其中$\mathbf f(n)$为$是否是 ...
- 洛谷——P2097 资料分发1
P2097 资料分发1 题目描述 有一些电脑,一部分电脑有双向数据线连接.如果一个电脑得到数据,它可以传送到的电脑都可以得到数据.现在,你有这个数据,问你至少将其输入几台电脑,才能使所有电脑得到数据. ...
- SqlHelper——只因为在人群中多看了你一眼
对SQLHelper,还是有一点陌生的,但是大多数人都在使用,我就有一种想了解并使用的意愿,于是查了很多资料,发现一片不错的博客,放在下面,作为自己或读者使用的材料. 一.SqlHelper 出场 不 ...
- 【模拟退火】poj2069 Super Star
题意:让你求空间内n个点的最小覆盖球. 模拟退火随机走的时候主要有这几种走法:①随机旋转角度. ②直接不随机,往最远的点的方向走,仅仅在尝试接受解的时候用概率.(最小圆/球覆盖时常用) ③往所有点的方 ...
- Activity(活动)生命周期(1)--返回栈
Android是使用任务(task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称为返回栈(Back stack).栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新的 ...
- [转]Spring Security学习总结一
[总结-含源码]Spring Security学习总结一(补命名空间配置) Posted on 2008-08-20 10:25 tangtb 阅读(43111) 评论(27) 编辑 收藏 所属分 ...
- Apache静态编译与动态编译详解
Apache拥有4层结构,从核心到外层的module.而外层的module可以用通过静态和动态两种方式与Apache共同工作.这也就引入下文的“动态”和“静态”两种编译安装方式: 静态编译: 编译的时 ...
- 【shiro】关于shiro匹配URL的小用法
今天涉及到这个地方 1.登录请求需要带着username和password一起过去,这样的话发出的请求就是:http://localhost:8080/wxSecond/welcome/login.h ...
- SQL Server 更新 触发器
- 复制代码 代码如下: create trigger TR_MasterTable_Update on MasterTable after update as if update ([Type])- ...