7.11 Update

我做题的时候发现这样写会RE

因为在使用双端队列优化SPFA的时候 在将一个点加入队列的时候,如果队列已经空了 那么一旦出现dis[Q.front()]就会RE 可以这样修改

  1. if(!Q.empty()) {
  2. if(dis[v[k]] < dis[Q.front()]) Q.push_front(v[k]);
  3. else Q.push_back(v[k]);
  4. }
  5. else Q.push_front(v[k]);

这样就不会RE了

期望时间复杂度:O(k*e或me)//k是增长很快的函数ackermann的反函数,2^65536次方也就5以下,但是可以被恶意数据卡掉,起复杂度就位(n*n ) //其中m为所有顶点进队的平均次数,可以证明m一般小于等于2n:“算法编程后实际运算情况表明m一般没有超过2n.事实上顶点入队次数m是一个不容易事先分析出来的数,但它确是一个随图的不同而略有不同的常数.所谓常数,就是与e无关,与n也无关,仅与边的权值分布有关.一旦图确定,权值确定,原点确定,m就是一个确定的常数.所以SPFA算法复杂度为O(e).证毕."(SPFA的论文)不过,这个证明是非常不严谨甚至错误的,事实上在bellman算法的论文中已有这方面的内容,所以国际上一般不承认SPFA算法。

SPFA算法有两个优化策略SLF和LLL——SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将j插入队首,否则插入队尾; LLL:Large Label Last 策略,设队首元素为i,队列中所有dist值的平均值为x,若dist(i)>x则将i插入到队尾,查找下一元素,直到找到某一i使得dist(i)<=x,则将i出队进行松弛操作。 SLF 可使速度提高 15 ~ 20%;SLF + LLL 可提高约 50%。 在实际的应用中SPFA的算法时间效率不是很稳定,为了避免最坏情况的出现,通常使用效率更加稳定的Dijkstra算法

上面这两段话呢,来自百度。

关于SPFA的时间复杂度,地球人应该都知道非常玄学的,近似可以看作O(看脸),

对于上面所说的最坏情况,我还记得有一次考试的题目中有一道最短路问题。

那道题的最后一组数据是用来卡SPFA的,(吓,出题人好毒瘤

这里我们不介绍LLL优化,

Only SLF优化


在每一次松弛操作的时候都已进入队列的操作

可是朴素的SPFA中将元素放到队列中时无序的,

如果改用一种很吊的队列的话,将其中的元素变得有点儿顺序

就可以起到优化的作用

这便是SLF优化

我们使用c++STL中的deque来实现上述操作

建议Pascal选手尽快转C++吧

下面就是代码(可能会很丑哦)

代码

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <deque>
  5. #include <algorithm>
  6.  
  7. const int maxnode = 1e4+;
  8. const int maxedge = 5e5+;
  9.  
  10. #define INF 2147483647
  11.  
  12. using namespace std;
  13.  
  14. deque<int> Q;
  15.  
  16. int first[maxnode], next[maxedge], n, m, s;
  17. int u[maxedge], v[maxedge], w[maxedge], dis[maxnode];
  18.  
  19. bool vis[maxnode];
  20.  
  21. inline int read() {
  22. char c = getchar();
  23. int x = , f = ;
  24. while (c < '' || c > '') {
  25. if(c == '-') f = -;
  26. c = getchar();
  27. }
  28. while (c <= '' && c >= '') {
  29. x = x* + c-'';
  30. c = getchar();
  31. }
  32. return x * f;
  33. }
  34.  
  35. inline void addedge(int from, int i) {
  36. next[i] = first[from];
  37. first[from] = i;
  38. }
  39.  
  40. inline void SPFA(int sta) {
  41. Q.push_back(sta), vis[sta] = true;
  42. while (!Q.empty()) {
  43. int x = Q.front();
  44. int k = first[x];
  45. Q.pop_front();
  46. while (k != -) {
  47. if (dis[v[k]] >= dis[u[k]] + w[k]) {
  48. dis[v[k]] = dis[u[k]] + w[k];
  49. if (!vis[v[k]]) {
  50. vis[v[k]] = ;
  51. if (dis[v[k]] < dis[Q.front()]) Q.push_front(v[k]);
  52. else Q.push_back(v[k]);
  53. }
  54. }
  55. k = next[k];
  56. }
  57. vis[x] = ;
  58. }
  59. }
  60.  
  61. int main() {
  62. n = read(), m = read(), s = read();
  63. for (int i=; i<=n; i++) dis[i] = INF;
  64. dis[s] = ;
  65. memset(first, -, sizeof(first));
  66. for (int i=; i<=m; i++) {
  67. u[i] = read(), v[i] = read(), w[i] = read();
  68. addedge (u[i], i);
  69. }
  70. SPFA(s);
  71. for (int i=; i<=n; i++) printf("%d ", dis[i]);
  72. }

关于SPFA的双端队列优化的更多相关文章

  1. poj 3259 Wormholes : spfa 双端队列优化 判负环 O(k*E)

    /** problem: http://poj.org/problem?id=3259 spfa判负环: 当有个点被松弛了n次,则这个点必定为负环中的一个点(n为点的个数) spfa双端队列优化: 维 ...

  2. Vijos1834 NOI2005 瑰丽华尔兹 动态规划 单调双端队列优化

    设dp[t][x][y]表示处理完前t个时间段,钢琴停留在(x,y)处,最多可以走多少个格子 转移时只需逆着当前倾斜的方向统计len个格子(len为时间区间的长度,len=t-s+1),如果遇到障碍就 ...

  3. POJ3662 SPFA//二分 + 双端队列最短路

    https://cn.vjudge.net/problem/12427/origin 题意:求1到N第K + 1大条边权最小的路径 首先想到dp递推,dp[x][y]表示到x这个点经过y条免费边的最小 ...

  4. P - The Shortest Path in Nya Graph-hdu4725(双端队列+拆点)

    题意:有N个点和N层..一层有X个点(0<=X<=N).两邻两层间有一条路花费C.还有M条小路在两个点之间.问从第一个点走到第N个点最短路是多少... 可以考虑在每一层增加一个点,这个点到 ...

  5. STL---deque(双端队列)

    Deque是一种优化了的.对序列两端元素进行添加和删除操作的基本序列容器.它允许较为快速地随机访问,但它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个映射结 ...

  6. 2601 电路维修 (双端队列bfs\优先队列bfs(最短路))

    描述 Ha'nyu是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女Rika,从而被收留在地球上.Rika的家里有一辆飞行车.有一天飞行车的电路板突然出现了故障,导致无法启动. 电路板 ...

  7. 自己动手实现java数据结构(四)双端队列

    1.双端队列介绍 在介绍双端队列之前,我们需要先介绍队列的概念.和栈相对应,在许多算法设计中,需要一种"先进先出(First Input First Output)"的数据结构,因 ...

  8. CH 2601 - 电路维修 - [双端队列BFS]

    题目链接:传送门 描述 Ha'nyu是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女Rika,从而被收留在地球上.Rika的家里有一辆飞行车.有一天飞行车的电路板突然出现了故障,导致 ...

  9. 【C++】STL常用容器总结之五:双端队列deque

    6.双端队列deque 所谓的deque是”double ended queue”的缩写,双端队列不论在尾部或头部插入元素,都十分迅速.而在中间插入元素则会比较费时,因为必须移动中间其他的元素.双端队 ...

随机推荐

  1. 危险的kill

    . ps -aux | grep -E "chk.*url.*py" | cut -c 10-15 | xargs kill -9 ps -x | grep -E "ch ...

  2. html5 弹性布局

    html5 弹性布局 一.移动开发常用技巧 Viewport基本知识 设置布局Viewport的各种信息1.width=device-width: 设置Viewport视口宽度等于设备宽度2.init ...

  3. 上百例Silverlight网站及演示汇总,供友参考

    毁灭2012 博客园 首页 新闻 新随笔 联系 管理 订阅 随笔- 125  文章- 0  评论- 446  上百例Silverlight网站及演示汇总,供友参考   今天我将发现的Silverlig ...

  4. 【CSU 1756】Prime

    http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1756 直接暴力O(n^2logn)过不了 两两算gcd 考虑每个数的范围[1,1000]统计一下即 ...

  5. [入门帮助] Kafka入门经典教程

    问题导读 1.Kafka独特设计在什么地方?2.Kafka如何搭建及创建topic.发送消息.消费消息?3.如何书写Kafka程序?4.数据传输的事务定义有哪三种?5.Kafka判断一个节点是否活着有 ...

  6. Runtime ----- 带你上道

    在IOS开发和学习过程中,我们经常会接触到一个词: Runtime  .很多开发者对之既熟悉又陌生,基本都是浅尝辄止,达不到灵活使用的水平(话说开发中也确实不经常用..)本文和大家一起研究一下,Run ...

  7. Linux下 FACL详解

    1. 什么是ACL ACL即Access Control List 主要的目的是提供传统的owner,group,others的read,write,execute权限之外的具体权限设置 ACL可以针 ...

  8. bzoj 2060: [Usaco2010 Nov]Visiting Cows 拜访奶牛【树形dp】

    设f[u][0/1]为u这个点不选/选,转移的时候从儿子转移,f[u][1]=sum(f[son][0])+1,f[u][0]=sum(max(f[son][0],f[e[i].to][1])) #i ...

  9. golang——随机数(math/rand包与crypto/rand包)

    1.math/rand 包 1.1.math/rand 包实现了伪随机数生成器 1.2.主要方法 (1)func Seed(seed int64) 设置随机种子,不设置则默认Seed(1) (2)fu ...

  10. Python安装第三方包(setup.py)

    在github上下载了records文件到本地. 解压文件 cmd切换到文件setup.py的目录下 先执行 python setup.py build 再执行python setup.py inst ...