主要思想是:

    初始时将起点加入队列。每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若某个相邻的点修改成功,则将其入队。直到队列为空时算法结束。
    这个算法,简单的说就是队列优化的bellman-ford,利用了每个点不会更新次数太多的特点发明的此算法。
SPFA 在形式上和广度优先搜索非常类似,不同的是广度优先搜索中一个点出了队列就不可能重新进入队列,但是SPFA中一个点可能在出队列之后再次被放入队列,也就是说一个点修改过其它的点之后,过了一段时间可能会获得更短的路径,于是再次用来修改其它的点,这样反复进行下去。
算法时间复杂度:O(kE)E是边数。K是常数,平均值为2
算法实现:
    dis[i]记录从起点si的最短路径,w[i][j]记录连接ij的边的长度。pre[v]记录前趋。
    team[1..n]为队列,头指针head,尾指针tail
    布尔数组exist[1..n]记录一个点是否现在存在在队列中。
    初始化:d[s]=0,d[v]=∞(vs),memset(exist,false,sizeof(exist));
    起点入队team[1]=s; head=0; tail=1;exist[s]=true;
    do
    {1、头指针向下移一位,取出指向的点u
    2、exist[u]=false;已被取出了队列
    3、foru相连的所有点v  //注意不要去枚举所有点,用数组模拟邻接表存储
       if (d[v]>d[u]+w[u][v])
         {   d[v]=d[u]+w[u][v];
             pre[v]=u;
             if (!exist[v]) //队列中不存在v点,v入队。
               {         //尾指针下移一位,v入队;
                    exist[v]=true;
                 }
          }
    }
    while (head < tail);
循环队列:
  采用循环队列能够降低队列大小,队列长度只需开到2*n+5即可。例题中的参考程序使用了循环队列。
完整代码:
  1. //spfa
  2.  
  3. #include<iostream>
  4. #include<cstdio>
  5. #include<cstring>
  6. using namespace std;
  7. const int maxn=0x7f;
  8. bool vis[];
  9. int map[][],dis[],queue[],path[];
  10. int n,m,head=,tail=,now;
  11.  
  12. void spfa(int x)
  13. {
  14. queue[head]=x;
  15. vis[x]=true;
  16. dis[x]=;
  17. path[x]=x;
  18. while(head<tail)
  19. {
  20. now=queue[head];
  21. for(int i=;i<=n;i++)
  22. {
  23. if(dis[i]>dis[now]+map[now][i])
  24. {
  25. dis[i]=dis[now]+map[now][i];
  26. path[i]=now;
  27. if(vis[i]==false)
  28. {
  29. queue[tail++]=i;
  30. vis[i]=true;
  31. }
  32. }
  33. }
  34. vis[now]=false;
  35. head++;
  36. }
  37. }
  38. void print(int st,int en)
  39. {
  40. int q[];
  41. int tot=;
  42. q[tot]=en;
  43. tot++;
  44. int temp=path[en];
  45. while(temp!=st)
  46. {
  47. q[tot]=temp;
  48. tot++;
  49. temp=path[temp];
  50. }
  51. q[tot]=st;
  52. for(int i=tot;i>=;i--)
  53. {
  54. if(i!=)
  55. printf("%d -- >",q[i]);
  56. else
  57. printf("%d",q[i]);
  58. }
  59. cout<<endl;
  60. }
  61. int main()
  62. {
  63. memset(map,maxn,sizeof(map));
  64. scanf("%d%d",&n,&m);
  65. int he,ta,len;
  66. for(int i=;i<=m;i++)
  67. {
  68. cin>>he>>ta>>len;
  69. map[he][ta]=map[ta][he]=len;
  70. }
  71. memset(dis,maxn,sizeof(dis));
  72. memset(vis,false,sizeof(vis));
  73. memset(queue,,sizeof(queue));
  74. int start,end;
  75. scanf("%d%d",&start,&end);
  76. spfa(start);
  77. printf("%d\n",dis[end]);
  78. print(start,end);
  79. return ;
  80. }

SPFA算法 O(kE)的更多相关文章

  1. 图论-最短路径--3、SPFA算法O(kE)

    SPFA算法O(kE) 主要思想是:     初始时将起点加入队列.每次从队列中取出一个元素,并对所有与它相邻的点进行修改,若某个相邻的点修改成功,则将其入队.直到队列为空时算法结束.     这个算 ...

  2. SPFA算法O(kE)

    SPFA算法O(kE) Dijkstra和Floyed是不断的试点.Dijkstra试最优点,Floyed试所有点. Bellman-Ford和SPFA是不断的试边.Bellman-Ford是盲目的试 ...

  3. 最短路径问题的Dijkstra和SPFA算法总结

    Dijkstra算法: 解决带非负权重图的单元最短路径问题.时间复杂度为O(V*V+E) 算法精髓:维持一组节点集合S,从源节点到该集合中的点的最短路径已被找到,算法重复从剩余的节点集V-S中选择最短 ...

  4. SPFA算法

    SPFA算法 一.算法简介 SPFA(Shortest Path Faster Algorithm)算法是求单源最短路径的一种算法,它是Bellman-ford的队列优化,它是一种十分高效的最短路算法 ...

  5. 最短路径--SPFA 算法

    适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径一 ...

  6. Bellman-Ford & SPFA 算法——求解单源点最短路径问题

    Bellman-Ford算法与另一个非常著名的Dijkstra算法一样,用于求解单源点最短路径问题.Bellman-ford算法除了可求解边权均非负的问题外,还可以解决存在负权边的问题(意义是什么,好 ...

  7. 最短路径算法之四——SPFA算法

    SPAF算法 求单源最短路的SPFA算法的全称是:Shortest Path Faster Algorithm,该算法是西南交通大学段凡丁于1994年发表的. 它可以在O(kE)的时间复杂度内求出源点 ...

  8. SPFA 算法详解

    适用范围:给定的图存在负权边,这时类似Dijkstra等算法便没有了用武之地,而Bellman-Ford算法的复杂度又过高,SPFA算法便 派上用场了. 我们约定有向加权图G不存在负权回路,即最短路径 ...

  9. 最短路径算法 4.SPFA算法(1)

    今天所说的就是常用的解决最短路径问题最后一个算法,这个算法同样是求连通图中单源点到其他结点的最短路径,功能和Bellman-Ford算法大致相同,可以求有负权的边的图,但不能出现负回路.但是SPFA算 ...

随机推荐

  1. bzoj千题计划208:bzoj3174: [Tjoi2013]拯救小矮人

    http://www.lydsy.com/JudgeOnline/problem.php?id=3174 按a+b从小到大排序,a+b小的在上面,先考虑让它逃出去 正确性不会证 感性理解一下,最后一个 ...

  2. c#的委托用法delegate

  3. nodejs图片总结

    今天终于把朴灵老师写的<深入浅出Node.js>给学习完了, 这本书不是一本简单的Node入门书籍,它没有停留在Node介绍或者框架.库的使用层面上,而是从不同的视角来揭示Node自己内在 ...

  4. 游程编码(Run Length Code)

    一.什么是游程编码 游程编码是一种比较简单的压缩算法,其基本思想是将重复且连续出现多次的字符使用(连续出现次数,某个字符)来描述. 比如一个字符串: AAAAABBBBCCC 使用游程编码可以将其描述 ...

  5. linux中使用corntab和shell脚本自动备份nginx日志,按天备份

    编写shell脚本,实现nginx日志每天自动备份到指定文件夹! 需要的命令mv , corntab -e(定时任务),shell脚本 这里先说一下corntab: https://www.cnblo ...

  6. 洛谷 P4128: bzoj 1815: [SHOI2006]有色图

    题目传送门:洛谷 P4128. 计数好题,原来是 13 年前就出现了经典套路啊.这题在当年应该很难吧. 题意简述: \(n\) 个点的完全图,点没有颜色,边有 \(m\) 种颜色,问本质不同的图的数量 ...

  7. oracle 级联查询 根路径

    级联查询有很多教程示例,但是没有找到求特定子孙到根的路径的例子,折腾了一番总算想出方法了. 现假设我们拥有一个菜单表t_menu,其中只有三个字段:id.name和parent_id.它们是具有父子关 ...

  8. oracle行转列

    wm_concat()函数 --创建表 create table test(id number,name varchar2(20)); --插入数据 insert into test values(1 ...

  9. 关于spring中Assert的应用(方法入参检测工具类)

    关于spring中Assert的应用(方法入参检测工具类) Web 应用在接受表单提交的数据后都需要对其进行合法性检查,如果表单数据不合法,请求将被驳回.类似的,当我们在编写类的方法时,也常常需要对方 ...

  10. springboot中url地址重写(urlwrite)

    在日常网站访问中,会把动态地址改造成伪静态地址. 例如: 访问新闻栏目 /col/1/,这是原有地址,如果这样访问,不利于搜索引擎检索收录,同时安全性也不是很好. 改造之后: /col/1.html. ...