先举出个例题:洛谷P3371 【模板】单源最短路径

一眼扫去:最短路径。

spfa不接受反驳。。。

附上代码:

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstdio>
  4. #include<queue>
  5. #define MAXN 10010
  6. #define MAX 999999999
  7. using namespace std;
  8. int n,m,s,c=1;
  9. int head[MAXN],path[MAXN];
  10. bool vis[MAXN];
  11. struct node{
  12. int next,to,w;
  13. }a[MAXN*100];
  14. inline int read(){
  15. int date=0,w=1;char c=0;
  16. while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
  17. while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
  18. return date*w;
  19. }
  20. inline int relax(int u,int v,int w){
  21. if(path[v]>path[u]+w){
  22. path[v]=path[u]+w;
  23. return 1;
  24. }
  25. return 0;
  26. }
  27. inline void add(int u,int v,int w){
  28. a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
  29. }
  30. void spfa(){
  31. int u,v;
  32. queue<int> q;
  33. for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
  34. path[s]=0;
  35. vis[s]=true;
  36. q.push(s);
  37. while(!q.empty()){
  38. u=q.front();
  39. q.pop();
  40. vis[u]=false;
  41. for(int i=head[u];i;i=a[i].next){
  42. v=a[i].to;
  43. if(relax(u,v,a[i].w)&&!vis[v]){
  44. vis[v]=true;
  45. q.push(v);
  46. }
  47. }
  48. }
  49. for(int i=1;i<=n;i++)printf("%d ",path[i]==MAX?2147483647:path[i]);
  50. }
  51. int main(){
  52. int u,v,w;
  53. n=read();m=read();s=read();
  54. for(int i=1;i<=m;i++){
  55. u=read();v=read();w=read();
  56. add(u,v,w);
  57. }
  58. spfa();
  59. return 0;
  60. }

然而遇到某些坑爹的题,比如USACO上的某些题,硬生生卡spfa啊!怎么办?

没事,我们有优化——SLF与LLL!


SLF优化:

SLF优化,即 Small Label First  策略,使用 双端队列 进行优化。

一般可以优化15%~20%,在竞赛中比较常用。

设从 u 扩展出了 v ,队列中队首元素为 k ,若 dis[ v ] < dis[ k ] ,则将 v 插入队首,否则插入队尾。

注:队列为空时直接插入队尾。

附代码:

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstdio>
  4. #include<deque>
  5. #define MAXN 10010
  6. #define MAXM 500010
  7. #define MAX 2147483647
  8. using namespace std;
  9. int n,m,s,t,c=1;
  10. int head[MAXN],path[MAXN];
  11. bool vis[MAXN];
  12. struct node{
  13. int next,to,w;
  14. }a[MAXM<<1];
  15. inline int read(){
  16. int date=0,w=1;char c=0;
  17. while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
  18. while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
  19. return date*w;
  20. }
  21. inline int relax(int u,int v,int w){
  22. if(path[v]>path[u]+w){
  23. path[v]=path[u]+w;
  24. return 1;
  25. }
  26. return 0;
  27. }
  28. inline void add(int u,int v,int w){
  29. a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
  30. }
  31. void spfa(){
  32. int u,v;
  33. deque<int> q;
  34. for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
  35. path[s]=0;
  36. vis[s]=true;
  37. q.push_back(s);
  38. while(!q.empty()){
  39. u=q.front();
  40. q.pop_front();
  41. vis[u]=false;
  42. for(int i=head[u];i;i=a[i].next){
  43. v=a[i].to;
  44. if(relax(u,v,a[i].w)&&!vis[v]){
  45. vis[v]=true;
  46. if(!q.empty()&&path[v]<path[q.front()])q.push_front(v);
  47. else q.push_back(v);
  48. }
  49. }
  50. }
  51. for(int i=1;i<=n;i++)printf("%d ",path[i]);
  52. printf("\n");
  53. }
  54. int main(){
  55. int u,v,w;
  56. n=read();m=read();s=read();
  57. for(int i=1;i<=m;i++){
  58. u=read();v=read();w=read();
  59. add(u,v,w);
  60. }
  61. spfa();
  62. return 0;
  63. }

LLL优化:

LLL优化,即 Large Label Last  策略,使用 双端队列 进行优化。

一般用SLF+LLL可以优化50%左右,但是在竞赛中并不常用LLL优化。

设队首元素为 k ,每次松弛时进行判断,队列中所有 dis 值的平均值为 x 。

若 dist[ k ] > x ,则将 k 插入到队尾,查找下一元素,直到找到某一个 k 使得 dis[ k ] <= x ,则将 k 出队进行松弛操作。

附代码:

  1. #include<iostream>
  2. #include<algorithm>
  3. #include<cstdio>
  4. #include<list>
  5. #define MAXN 10010
  6. #define MAXM 500010
  7. #define MAX 2147483647
  8. using namespace std;
  9. int n,m,s,t,c=1;
  10. int head[MAXN],path[MAXN];
  11. bool vis[MAXN];
  12. struct node{
  13. int next,to,w;
  14. }a[MAXM<<1];
  15. inline int read(){
  16. int date=0,w=1;char c=0;
  17. while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
  18. while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
  19. return date*w;
  20. }
  21. inline int relax(int u,int v,int w){
  22. if(path[v]>path[u]+w){
  23. path[v]=path[u]+w;
  24. return 1;
  25. }
  26. return 0;
  27. }
  28. inline void add(int u,int v,int w){
  29. a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
  30. }
  31. void spfa(){
  32. int u,v,num=0;
  33. long long x=0;
  34. list<int> q;
  35. for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
  36. path[s]=0;
  37. vis[s]=true;
  38. q.push_back(s);
  39. num++;
  40. while(!q.empty()){
  41. u=q.front();
  42. q.pop_front();
  43. num--;x-=path[u];
  44. while(num&&path[u]>x/num){
  45. q.push_back(u);
  46. u=q.front();
  47. q.pop_front();
  48. }
  49. vis[u]=false;
  50. for(int i=head[u];i;i=a[i].next){
  51. v=a[i].to;
  52. if(relax(u,v,a[i].w)&&!vis[v]){
  53. vis[v]=true;
  54. if(!q.empty()&&path[v]<path[q.front()])q.push_front(v);
  55. else q.push_back(v);
  56. num++;x+=path[v];
  57. }
  58. }
  59. }
  60. for(int i=1;i<=n;i++)printf("%d ",path[i]);
  61. printf("\n");
  62. }
  63. int main(){
  64. int u,v,w;
  65. n=read();m=read();s=read();
  66. for(int i=1;i<=m;i++){
  67. u=read();v=read();w=read();
  68. add(u,v,w);
  69. }
  70. spfa();
  71. return 0;
  72. }

后记:

附上洛谷上的三次提交:

朴素spfa:Accepted  100

336ms /  7.92MB 
代码:1.19KB C++

spfa+SLF: Accepted  100

316ms /  7.89MB 
代码:1.33KB C++

spfa+SLF+LLL: Accepted  100

316ms /  8.08MB 
代码:1.45KB C++

显然,SLF这个优化已经足够了。

再说,就算卡spfa+优化,不就5~10分嘛。。。

$Update 2018.7.29:$:

$NOI2018Day1T1$竟然真的卡了$SPFA$!!!

并且卡了$40$分!!!

出题人你说你卡个$10$分、$20$分也就算了,居然卡了$40$分!!!

大毒瘤。。。

所以对于正权图还是乖乖写堆优化$Dijkstra$吧。。。

附上讲解:

Dijkstra的堆优化

SPFA的两个优化:SLF与LLL的更多相关文章

  1. SPFA 的两个优化

    From NOCOW SPFA算法有两个优化算法 SLF 和 LLL: SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将 ...

  2. SPFA的两个优化

    评测题:洛谷[模板]单源最短路径 不加任何优化: queue<int>q; void spfa(ll s) { ;i<=n;i++) d[i]=(ll)(); d[s]=;q.pus ...

  3. SPFA的两种优化

    SPFA是可以优化的,这个大家都是晓得的吧. 下面介绍两种SPFA的神奇优化(我只代码实现了的一种) SLF:Small Label First策略,设要加入的节点是j,队首元素为i,若dist(j) ...

  4. SPFA的两个(卡时)优化

    SPFA算法有两个优化算法 SLF 和 LLL: SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将j插入队首,否则插入队 ...

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

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

  6. WebGPU学习(十一):学习两个优化:“reuse render command buffer”和“dynamic uniform buffer offset”

    大家好,本文介绍了"reuse render command buffer"和"dynamic uniform buffer offset"这两个优化,以及Ch ...

  7. ACM/ICPC 之 SPFA练习两道(ZOJ3088-ZOJ3103)

    两道题都需要进行双向SPFA,比范例复杂,代码也较长,其中第二题应该可以用DFS或者BFS做,如果用DFS可能需要的剪枝较多. ZOJ3088-Easter Holydays //利用SPFA找出下降 ...

  8. ACM/ICPC 之 SPFA范例两道(POJ3268-POJ3259)

    两道以SPFA算法求解的最短路问题,比较水,第二题需要掌握如何判断负权值回路. POJ3268-Silver Cow Party //计算正逆最短路径之和的最大值 //Time:32Ms Memory ...

  9. [MySQL] 两个优化数据库表的简单方法--18.3

    这里介绍两个简单的优化MySQL数据库表的方法 一.定期分析表和检查表 1.分析表语法如下: alalyze [local|no_write_to_binlog] table table_name1[ ...

随机推荐

  1. CSS:水平居中与垂直居中

    CSS居中算是一个比较基础的问题,在实际运用中,需要考虑到的一般是两种情况,一种是主要是表现为文字,图片等行内元素的居中,一种是指 div 等块级标签元素的居中. 水平居中 1.行内元素 行内元素(主 ...

  2. window环境下使用PHP OpenSSL扩展函数返回false的原因

    window环境下使用PHP OpenSSL扩展函数返回false的原因(openssl_pkey_new) 使用的开发环境是PHPstudy ,在使用OpenSSL的函数openssl_pkey_n ...

  3. Ubuntu 16.04下使用Wine安装Notepad++

    说明: 1.使用的Wine版本是深度出品(Deepin),已经精简了很多没用的配置,使启动能非常快,占用资源小. 2.关于没有.wine文件夹的解决方法:在命令行上运行winecfg: 下载: (链接 ...

  4. win8.1安装VMware Error:This product may not be installed on a comuputer that has Microsoft HyperV installed

    之前用的win7,安装虚机没遇到这问题,换了win8.1后,再安装虚机,就会出现下面的错误.没办法,还是记录一下吧. Error:This product may not be installed o ...

  5. Scut游戏服务器引擎5.6.3.5发布

    版本:5.6.3.5 (2013-11-25) 1. 优化实体ChangeKey队列,减少写库IO(默认为5分钟写入一次数据库) 2. 优化Protobuf序列化启用自动GZip压缩,减少Redis内 ...

  6. metasploit study

    load db_trackerdb_nmap -T Aggressive -sV -n -O -v 192.168.0.107 绑定shelluse exploit/windows/smb/ms08_ ...

  7. 转:java工程师成神之路

    转自: http://www.hollischuang.com/archives/489 一.基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 htt ...

  8. 移动端去掉按钮button默认样式

    <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...

  9. 协程(Coroutine)并不是真正的多线程(转)

    自:http://www.zhihu.com/question/23895384 说到Coroutine,我们必须提到两个更远的东西.在操作系统(os)级别,有进程(process)和线程(threa ...

  10. 【转载】ASP.Net请求处理机制初步探索之旅 - Part 3 管道

    开篇:上一篇我们了解了一个ASP.Net页面请求的核心处理入口,它经历了三个重要的入口,分别是:ISAPIRuntime.ProcessRequest().HttpRuntime.ProcessReq ...