算法笔记_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 那样统一和直 ...
随机推荐
- 字符串Hash相关
其实也并不是什么特别难的算法,但是我个人实在是不太喜欢字符串之类的东西(字符串神马的真的是麻烦),于是一直拖着不想看,然后模板题之类的也懒得做. Hash的思想其实也没什么复杂的,就是给定一系列字符串 ...
- plsql分支,循环,异常
pl/sql 分支,循环和异常分支: DECLARE BEGIN END; 循环:loop,while,for 1.LOOP EXIT WHEN ...
- json_decode转码无效
由于最近从原来常用的utf-8的字符转到了gbk:所以,在用json_decode的时候遇到了返回为空: 经查找发现是json_decode和json_encode只针对utf8字符串有效: 于是用到 ...
- js中复制方法总结
js中有深拷贝和浅拷贝两种复制形式,下面总结一下常用方法,方便平时工作复习使用 一.浅拷贝 1.json对象浅拷贝 var newObj = JSON.parse(JSON.stringify( so ...
- Codeforces Round #294 (Div. 2) A and B and Lecture Rooms(LCA 倍增)
A and B and Lecture Rooms time limit per test 2 seconds memory limit per test 256 megabytes input st ...
- Sqli-labs less 4
Less-4 我们使用?id=1" 注入代码后,我们得到像这样的一个错误: You have an error in your SQL syntax; check the manual th ...
- Oracle关于锁的几种类型和参数
设立封锁机制主要是为了对并发操作进行控制,对干扰进行封锁,保证数据的一致性和准确性.Oracle数据库封锁方式有三种:共享封锁,独占封锁,共享更新封锁 封锁类型 Oracle RDBMS的封锁类型可分 ...
- hdu 4747 Mex( 线段树? 不,区间处理就行(dp?))
Mex Time Limit: 15000/5000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Total Submis ...
- mysql函数的使用create function myfunction(...
use test //必须在某个数据库下面创建 delimiter $ //创建 CREATE FUNCTION myFunction(ln int, ls int) //参数这里不能加def ...
- 8VC Venture Cup 2016 - Final Round (Div. 2 Edition) C. XOR Equation 数学
C. XOR Equation 题目连接: http://www.codeforces.com/contest/635/problem/C Description Two positive integ ...