7.11 Update

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

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

if(!Q.empty()) {
if(dis[v[k]] < dis[Q.front()]) Q.push_front(v[k]);
else Q.push_back(v[k]);
}
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++吧

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

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <deque>
#include <algorithm> const int maxnode = 1e4+;
const int maxedge = 5e5+; #define INF 2147483647 using namespace std; deque<int> Q; int first[maxnode], next[maxedge], n, m, s;
int u[maxedge], v[maxedge], w[maxedge], dis[maxnode]; bool vis[maxnode]; inline int read() {
char c = getchar();
int x = , f = ;
while (c < '' || c > '') {
if(c == '-') f = -;
c = getchar();
}
while (c <= '' && c >= '') {
x = x* + c-'';
c = getchar();
}
return x * f;
} inline void addedge(int from, int i) {
next[i] = first[from];
first[from] = i;
} inline void SPFA(int sta) {
Q.push_back(sta), vis[sta] = true;
while (!Q.empty()) {
int x = Q.front();
int k = first[x];
Q.pop_front();
while (k != -) {
if (dis[v[k]] >= dis[u[k]] + w[k]) {
dis[v[k]] = dis[u[k]] + w[k];
if (!vis[v[k]]) {
vis[v[k]] = ;
if (dis[v[k]] < dis[Q.front()]) Q.push_front(v[k]);
else Q.push_back(v[k]);
}
}
k = next[k];
}
vis[x] = ;
}
} int main() {
n = read(), m = read(), s = read();
for (int i=; i<=n; i++) dis[i] = INF;
dis[s] = ;
memset(first, -, sizeof(first));
for (int i=; i<=m; i++) {
u[i] = read(), v[i] = read(), w[i] = read();
addedge (u[i], i);
}
SPFA(s);
for (int i=; i<=n; i++) printf("%d ", dis[i]);
}

关于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. docker映射端口与ssh访问或容器访问

    映射端口 -d 后台执行 -p映射端口 --privileged 可以使用systemctl # docker run --privileged -d -p 9000:80 jiqing9006/ce ...

  2. sql加一个%号是什么意思

    sql%notfound 是异常SQL%ROWCOUNT SQL语句执行影响的行数SQL%FOUND SQL语句是否成功执行SQL%NOTFOUND SQL语句是否成功执行SQL%ISOPEN 游标是 ...

  3. flash、flex builder、flash builder、 air的关系

    flash VS flex builder flash被adobe收购的时候是flash8,已经可以AS2面向对象了. 而被adobe收购后,adobe准备把flash打造成一个开发工具.就比如JBU ...

  4. android 制作9.png图片

    什么叫.9.PNG呢,这是安卓开发里面的一种特殊的图片   这种格式的图片在android 环境下具有自适应调节大小的能力.   (1)允许开发人员定义可扩展区域,当需要延伸图片以填充比图片本身更大区 ...

  5. 从缓冲上看阻塞与非阻塞socket在发送接收上的区别(转载)

    转自:http://blog.chinaunix.net/uid-24517549-id-4044877.html   首先socket在默认情况下是阻塞状态的,这就使得发送以及接收操作处于阻塞的状态 ...

  6. E20171102-E

    segment   n. 环节; 部分,段落; [计算机] (字符等的) 分段; [动物学] 节片; distinct  adj. 明显的,清楚的; 卓越的,不寻常的; 有区别的; 确切的;

  7. 洛谷 P3121 [USACO15FEB]审查(黄金)Censoring (Gold) 【AC自动机+栈】

    这个和bzoj同名题不一样,有多个匹配串 但是思路是一样的,写个AC自动机,同样是开两个栈,一个存字符,一个存当前点在trie树上的位置,然后如果到了某个匹配串的末尾,则弹栈 #include< ...

  8. bzoj 1620: [Usaco2008 Nov]Time Management 时间管理【贪心】

    按s从大到小排序,逆推时间模拟工作 #include<iostream> #include<cstdio> #include<algorithm> using na ...

  9. javascript实现引用数据类型的深拷贝和浅拷贝详解

    关于引用类型值的详解,请看另一篇随笔 https://www.cnblogs.com/jinbang/p/10346584.html 深拷贝和浅拷贝,也就是引用数据类型栈和堆的知识点.深浅拷贝的原型都 ...

  10. java entity

    对java实体类的众多理解: A .就是属性类,通常定义在model层里面 B. 一般的实体类对应一个数据表,其中的属性对应数据表中的字段.好处:1.对对象实体的封装,体现OO思想.2.属性可以对字段 ...