目录

1 问题描述

2 解决方案

2.1 具体编码

 


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):

  1. package com.liuzhen.chapter9;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.Scanner;
  5.  
  6. public class Spfa {
  7.  
  8. public long[] result; //用于得到第s个顶点到其它顶点之间的最短距离
  9.  
  10. //内部类,用于存放图的具体边数据
  11. class edge {
  12. public int a; //边的起点
  13. public int b; //边的终点
  14. public int value; //边的权值
  15.  
  16. edge(int a, int b, int value) {
  17. this.a = a;
  18. this.b = b;
  19. this.value = value;
  20. }
  21. }
  22. /*
  23. * 参数n:给定图的顶点个数
  24. * 参数s:求取第s个顶点到其它所有顶点之间的最短距离
  25. * 参数edge:给定图的具体边
  26. * 函数功能:如果给定图不含负权回路,则可以得到最终结果,如果含有负权回路,则不能得到最终结果
  27. */
  28. public boolean getShortestPaths(int n, int s, edge[] A) {
  29. ArrayList<Integer> list = new ArrayList<Integer>();
  30. result = new long[n];
  31. boolean[] used = new boolean[n];
  32. int[] num = new int[n];
  33. for(int i = 0;i < n;i++) {
  34. result[i] = Integer.MAX_VALUE;
  35. used[i] = false;
  36. }
  37. result[s] = 0; //第s个顶点到自身距离为0
  38. used[s] = true; //表示第s个顶点进入数组队
  39. num[s] = 1; //表示第s个顶点已被遍历一次
  40. list.add(s); //第s个顶点入队
  41. while(list.size() != 0) {
  42. int a = list.get(0); //获取数组队中第一个元素
  43. list.remove(0); //删除数组队中第一个元素
  44. for(int i = 0;i < A.length;i++) {
  45. //当list数组队的第一个元素等于边A[i]的起点时
  46. if(a == A[i].a && result[A[i].b] > result[A[i].a] + A[i].value) {
  47. result[A[i].b] = result[A[i].a] + A[i].value;
  48. if(!used[A[i].b]) {
  49. list.add(A[i].b);
  50. num[A[i].b]++;
  51. if(num[A[i].b] > n)
  52. return false;
  53. used[A[i].b] = true; //表示边A[i]的终点b已进入数组队
  54. }
  55. }
  56. }
  57. used[a] = false; //顶点a出数组对
  58. }
  59. return true;
  60. }
  61.  
  62. public static void main(String[] args) {
  63. Spfa test = new Spfa();
  64. Scanner in = new Scanner(System.in);
  65. System.out.println("请输入一个图的顶点总数n起点下标s和边总数p:");
  66. int n = in.nextInt();
  67. int s = in.nextInt();
  68. int p = in.nextInt();
  69. edge[] A = new edge[p];
  70. System.out.println("请输入具体边的数据:");
  71. for(int i = 0;i < p;i++) {
  72. int a = in.nextInt();
  73. int b = in.nextInt();
  74. int value = in.nextInt();
  75. A[i] = test.new edge(a, b, value);
  76. }
  77. if(test.getShortestPaths(n, s, A)) {
  78. for(int i = 0;i < test.result.length;i++)
  79. System.out.print(test.result[i]+" ");
  80. } else
  81. System.out.println("给定图存在负环,没有最短距离");
  82. }
  83. }

运行结果:

  1. 请输入一个图的顶点总数n起点下标s和边总数p
  2. 6 1 18
  3. 请输入具体边的数据:
  4. 0 1 6
  5. 0 2 3
  6. 1 2 2
  7. 1 3 5
  8. 2 3 3
  9. 2 4 4
  10. 3 4 2
  11. 3 5 3
  12. 4 5 5
  13. 1 0 6
  14. 2 0 3
  15. 2 1 2
  16. 3 1 5
  17. 3 2 3
  18. 4 2 4
  19. 4 3 2
  20. 5 3 3
  21. 5 4 5
  22. 5 0 2 5 6 8

参考资料:

1. SPFA算法详解

算法笔记_071:SPFA算法简单介绍(Java)的更多相关文章

  1. 算法笔记_221:串的简单处理(Java)

    目录 1 问题描述 2 解决方案   1 问题描述 串的处理在实际的开发工作中,对字符串的处理是最常见的编程任务.本题目即是要求程序对用户输入的串进行处理.具体规则如下:1. 把每个单词的首字母变为大 ...

  2. 算法笔记之KMP算法

    本文是<算法笔记>KMP算法章节的阅读笔记,文中主要内容来源于<算法笔记>.本文主要介绍了next数组.KMP算法及其应用以及对KMP算法的优化. KMP算法主要用于解决字符串 ...

  3. (转)简单介绍java Enumeration

    简单介绍java Enumeration 分类: java技术备份 java数据结构objectstringclass存储 Enumeration接口  Enumeration接口本身不是一个数据结构 ...

  4. Bellman-Ford算法的改进---SPFA算法

    传送门: Dijkstra Bellman-Ford SPFA Floyd 1.算法思想 Bellman-Ford算法时间复杂度比较高,在于Bellman-Ford需要递推n次,每次递推需要扫描所有的 ...

  5. 算法笔记_054:Prim算法(Java)

    目录 1 问题描述 2 解决方案 2.1 贪心法   1 问题描述 何为Prim算法? 此处引用网友博客中一段介绍(PS:个人感觉网友的这篇博客对于Prim算法讲解的很清楚,本文与之相区别的地方在于具 ...

  6. 算法笔记_066:Kruskal算法详解(Java)

    目录 1 问题描述 2 解决方案 2.1 构造最小生成树示例 2.2 伪码及时间效率分析 2.3 具体编码(最佳时间效率)   1 问题描述 何为Kruskal算法? 该算法功能:求取加权连通图的最小 ...

  7. JMeter学习笔记2-图形界面简单介绍

    废话少说直接干活的给: 一.打开和运行JMeter,出现UI界面.如图下所示: 工具栏:常见操作的图标集合,有New(新建), Template(模板) ,Save(保存),Start(开始) ,St ...

  8. 算法笔记--lca倍增算法

    算法笔记 模板: vector<int>g[N]; vector<int>edge[N]; ][N]; int deep[N]; int h[N]; void dfs(int ...

  9. 简单介绍 Java 构造器

    导读 构造器是编程的强大组件.使用它们来释放 Java 的全部潜力. 在开源.跨平台编程领域,Java 无疑(?)是无可争议的重量级语言.尽管有许多伟大的跨平台框架,但很少有像 Java 那样统一和直 ...

随机推荐

  1. python之并发编程(线程\进程\协程)

    一.进程和线程 1.进程 假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源.是 ...

  2. Bzoj2818 Gcd(莫比乌斯反演)

    题面 题意都在题目里面了 题解 你可以把题意看成这个东西 $$ \sum_{i=1}^n\sum_{j=1}^m\mathbf f(gcd(i,j)) $$ 其中$\mathbf f(n)$为$是否是 ...

  3. 洛谷——P2097 资料分发1

    P2097 资料分发1 题目描述 有一些电脑,一部分电脑有双向数据线连接.如果一个电脑得到数据,它可以传送到的电脑都可以得到数据.现在,你有这个数据,问你至少将其输入几台电脑,才能使所有电脑得到数据. ...

  4. SqlHelper——只因为在人群中多看了你一眼

    对SQLHelper,还是有一点陌生的,但是大多数人都在使用,我就有一种想了解并使用的意愿,于是查了很多资料,发现一片不错的博客,放在下面,作为自己或读者使用的材料. 一.SqlHelper 出场 不 ...

  5. 【模拟退火】poj2069 Super Star

    题意:让你求空间内n个点的最小覆盖球. 模拟退火随机走的时候主要有这几种走法:①随机旋转角度. ②直接不随机,往最远的点的方向走,仅仅在尝试接受解的时候用概率.(最小圆/球覆盖时常用) ③往所有点的方 ...

  6. Activity(活动)生命周期(1)--返回栈

    Android是使用任务(task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称为返回栈(Back stack).栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新的 ...

  7. [转]Spring Security学习总结一

    [总结-含源码]Spring Security学习总结一(补命名空间配置) Posted on 2008-08-20 10:25 tangtb 阅读(43111) 评论(27)  编辑  收藏 所属分 ...

  8. Apache静态编译与动态编译详解

    Apache拥有4层结构,从核心到外层的module.而外层的module可以用通过静态和动态两种方式与Apache共同工作.这也就引入下文的“动态”和“静态”两种编译安装方式: 静态编译: 编译的时 ...

  9. 【shiro】关于shiro匹配URL的小用法

    今天涉及到这个地方 1.登录请求需要带着username和password一起过去,这样的话发出的请求就是:http://localhost:8080/wxSecond/welcome/login.h ...

  10. SQL Server 更新 触发器

    - 复制代码 代码如下: create trigger TR_MasterTable_Update on MasterTable after update as if update ([Type])- ...