SPFA的两个优化:SLF与LLL
先举出个例题:洛谷P3371 【模板】单源最短路径
一眼扫去:最短路径。
spfa不接受反驳。。。
附上代码:
- #include<iostream>
- #include<algorithm>
- #include<cstdio>
- #include<queue>
- #define MAXN 10010
- #define MAX 999999999
- using namespace std;
- int n,m,s,c=1;
- int head[MAXN],path[MAXN];
- bool vis[MAXN];
- struct node{
- int next,to,w;
- }a[MAXN*100];
- inline int read(){
- int date=0,w=1;char c=0;
- while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
- while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
- return date*w;
- }
- inline int relax(int u,int v,int w){
- if(path[v]>path[u]+w){
- path[v]=path[u]+w;
- return 1;
- }
- return 0;
- }
- inline void add(int u,int v,int w){
- a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
- }
- void spfa(){
- int u,v;
- queue<int> q;
- for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
- path[s]=0;
- vis[s]=true;
- q.push(s);
- while(!q.empty()){
- u=q.front();
- q.pop();
- vis[u]=false;
- for(int i=head[u];i;i=a[i].next){
- v=a[i].to;
- if(relax(u,v,a[i].w)&&!vis[v]){
- vis[v]=true;
- q.push(v);
- }
- }
- }
- for(int i=1;i<=n;i++)printf("%d ",path[i]==MAX?2147483647:path[i]);
- }
- int main(){
- int u,v,w;
- n=read();m=read();s=read();
- for(int i=1;i<=m;i++){
- u=read();v=read();w=read();
- add(u,v,w);
- }
- spfa();
- return 0;
- }
然而遇到某些坑爹的题,比如USACO上的某些题,硬生生卡spfa啊!怎么办?
没事,我们有优化——SLF与LLL!
SLF优化:
SLF优化,即 Small Label First 策略,使用 双端队列 进行优化。
一般可以优化15%~20%,在竞赛中比较常用。
设从 u 扩展出了 v ,队列中队首元素为 k ,若 dis[ v ] < dis[ k ] ,则将 v 插入队首,否则插入队尾。
注:队列为空时直接插入队尾。
附代码:
- #include<iostream>
- #include<algorithm>
- #include<cstdio>
- #include<deque>
- #define MAXN 10010
- #define MAXM 500010
- #define MAX 2147483647
- using namespace std;
- int n,m,s,t,c=1;
- int head[MAXN],path[MAXN];
- bool vis[MAXN];
- struct node{
- int next,to,w;
- }a[MAXM<<1];
- inline int read(){
- int date=0,w=1;char c=0;
- while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
- while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
- return date*w;
- }
- inline int relax(int u,int v,int w){
- if(path[v]>path[u]+w){
- path[v]=path[u]+w;
- return 1;
- }
- return 0;
- }
- inline void add(int u,int v,int w){
- a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
- }
- void spfa(){
- int u,v;
- deque<int> q;
- for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
- path[s]=0;
- vis[s]=true;
- q.push_back(s);
- while(!q.empty()){
- u=q.front();
- q.pop_front();
- vis[u]=false;
- for(int i=head[u];i;i=a[i].next){
- v=a[i].to;
- if(relax(u,v,a[i].w)&&!vis[v]){
- vis[v]=true;
- if(!q.empty()&&path[v]<path[q.front()])q.push_front(v);
- else q.push_back(v);
- }
- }
- }
- for(int i=1;i<=n;i++)printf("%d ",path[i]);
- printf("\n");
- }
- int main(){
- int u,v,w;
- n=read();m=read();s=read();
- for(int i=1;i<=m;i++){
- u=read();v=read();w=read();
- add(u,v,w);
- }
- spfa();
- return 0;
- }
LLL优化:
LLL优化,即 Large Label Last 策略,使用 双端队列 进行优化。
一般用SLF+LLL可以优化50%左右,但是在竞赛中并不常用LLL优化。
设队首元素为 k ,每次松弛时进行判断,队列中所有 dis 值的平均值为 x 。
若 dist[ k ] > x ,则将 k 插入到队尾,查找下一元素,直到找到某一个 k 使得 dis[ k ] <= x ,则将 k 出队进行松弛操作。
附代码:
- #include<iostream>
- #include<algorithm>
- #include<cstdio>
- #include<list>
- #define MAXN 10010
- #define MAXM 500010
- #define MAX 2147483647
- using namespace std;
- int n,m,s,t,c=1;
- int head[MAXN],path[MAXN];
- bool vis[MAXN];
- struct node{
- int next,to,w;
- }a[MAXM<<1];
- inline int read(){
- int date=0,w=1;char c=0;
- while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
- while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
- return date*w;
- }
- inline int relax(int u,int v,int w){
- if(path[v]>path[u]+w){
- path[v]=path[u]+w;
- return 1;
- }
- return 0;
- }
- inline void add(int u,int v,int w){
- a[c].to=v;a[c].w=w;a[c].next=head[u];head[u]=c++;
- }
- void spfa(){
- int u,v,num=0;
- long long x=0;
- list<int> q;
- for(int i=1;i<=n;i++){path[i]=MAX;vis[i]=false;}
- path[s]=0;
- vis[s]=true;
- q.push_back(s);
- num++;
- while(!q.empty()){
- u=q.front();
- q.pop_front();
- num--;x-=path[u];
- while(num&&path[u]>x/num){
- q.push_back(u);
- u=q.front();
- q.pop_front();
- }
- vis[u]=false;
- for(int i=head[u];i;i=a[i].next){
- v=a[i].to;
- if(relax(u,v,a[i].w)&&!vis[v]){
- vis[v]=true;
- if(!q.empty()&&path[v]<path[q.front()])q.push_front(v);
- else q.push_back(v);
- num++;x+=path[v];
- }
- }
- }
- for(int i=1;i<=n;i++)printf("%d ",path[i]);
- printf("\n");
- }
- int main(){
- int u,v,w;
- n=read();m=read();s=read();
- for(int i=1;i<=m;i++){
- u=read();v=read();w=read();
- add(u,v,w);
- }
- spfa();
- return 0;
- }
后记:
附上洛谷上的三次提交:
朴素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的更多相关文章
- SPFA 的两个优化
From NOCOW SPFA算法有两个优化算法 SLF 和 LLL: SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将 ...
- SPFA的两个优化
评测题:洛谷[模板]单源最短路径 不加任何优化: queue<int>q; void spfa(ll s) { ;i<=n;i++) d[i]=(ll)(); d[s]=;q.pus ...
- SPFA的两种优化
SPFA是可以优化的,这个大家都是晓得的吧. 下面介绍两种SPFA的神奇优化(我只代码实现了的一种) SLF:Small Label First策略,设要加入的节点是j,队首元素为i,若dist(j) ...
- SPFA的两个(卡时)优化
SPFA算法有两个优化算法 SLF 和 LLL: SLF:Small Label First 策略,设要加入的节点是j,队首元素为i,若dist(j)<dist(i),则将j插入队首,否则插入队 ...
- poj 3259 Wormholes : spfa 双端队列优化 判负环 O(k*E)
/** problem: http://poj.org/problem?id=3259 spfa判负环: 当有个点被松弛了n次,则这个点必定为负环中的一个点(n为点的个数) spfa双端队列优化: 维 ...
- WebGPU学习(十一):学习两个优化:“reuse render command buffer”和“dynamic uniform buffer offset”
大家好,本文介绍了"reuse render command buffer"和"dynamic uniform buffer offset"这两个优化,以及Ch ...
- ACM/ICPC 之 SPFA练习两道(ZOJ3088-ZOJ3103)
两道题都需要进行双向SPFA,比范例复杂,代码也较长,其中第二题应该可以用DFS或者BFS做,如果用DFS可能需要的剪枝较多. ZOJ3088-Easter Holydays //利用SPFA找出下降 ...
- ACM/ICPC 之 SPFA范例两道(POJ3268-POJ3259)
两道以SPFA算法求解的最短路问题,比较水,第二题需要掌握如何判断负权值回路. POJ3268-Silver Cow Party //计算正逆最短路径之和的最大值 //Time:32Ms Memory ...
- [MySQL] 两个优化数据库表的简单方法--18.3
这里介绍两个简单的优化MySQL数据库表的方法 一.定期分析表和检查表 1.分析表语法如下: alalyze [local|no_write_to_binlog] table table_name1[ ...
随机推荐
- CSS:水平居中与垂直居中
CSS居中算是一个比较基础的问题,在实际运用中,需要考虑到的一般是两种情况,一种是主要是表现为文字,图片等行内元素的居中,一种是指 div 等块级标签元素的居中. 水平居中 1.行内元素 行内元素(主 ...
- window环境下使用PHP OpenSSL扩展函数返回false的原因
window环境下使用PHP OpenSSL扩展函数返回false的原因(openssl_pkey_new) 使用的开发环境是PHPstudy ,在使用OpenSSL的函数openssl_pkey_n ...
- Ubuntu 16.04下使用Wine安装Notepad++
说明: 1.使用的Wine版本是深度出品(Deepin),已经精简了很多没用的配置,使启动能非常快,占用资源小. 2.关于没有.wine文件夹的解决方法:在命令行上运行winecfg: 下载: (链接 ...
- 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 ...
- Scut游戏服务器引擎5.6.3.5发布
版本:5.6.3.5 (2013-11-25) 1. 优化实体ChangeKey队列,减少写库IO(默认为5分钟写入一次数据库) 2. 优化Protobuf序列化启用自动GZip压缩,减少Redis内 ...
- metasploit study
load db_trackerdb_nmap -T Aggressive -sV -n -O -v 192.168.0.107 绑定shelluse exploit/windows/smb/ms08_ ...
- 转:java工程师成神之路
转自: http://www.hollischuang.com/archives/489 一.基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 htt ...
- 移动端去掉按钮button默认样式
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="UTF-8&quo ...
- 协程(Coroutine)并不是真正的多线程(转)
自:http://www.zhihu.com/question/23895384 说到Coroutine,我们必须提到两个更远的东西.在操作系统(os)级别,有进程(process)和线程(threa ...
- 【转载】ASP.Net请求处理机制初步探索之旅 - Part 3 管道
开篇:上一篇我们了解了一个ASP.Net页面请求的核心处理入口,它经历了三个重要的入口,分别是:ISAPIRuntime.ProcessRequest().HttpRuntime.ProcessReq ...