zoukankan      html  css  js  c++  java
  • SPFA 介绍

    简介

    即 Shortest Path Faster Algorithm。

    一种基于松弛(relax)操作的最短路算法。

    支持负权。

    能找到某个结点出发到所有结点的最短路,或者报告某些最短路不存在。

    不过呢:

    很多时候我们并不需要那么多无用的松弛操作。

    很显然,只有上一次被松弛的结点,所连接的边,才有可能引起下一次的松弛操作。

    那么我们用队列来维护“哪些结点可能会引起松弛操作”,就能只访问必要的边了。

    提醒

    虽然在大多数情况下 SPFA 跑得很快,但其最坏情况下的时间复杂度为 (operatorname{O}(nm)),将其卡到这个复杂度也是不难的,所以考试时要谨慎使用(在没有负权边时最好使用 Dijkstra 算法,在有负权边且题目中的图没有特殊性质时,若 SPFA 是标算的一部分,题目不应当给出 Bellman-Ford 算法无法通过的数据范围)。

    除了队列优化(SPFA)之外,Bellman-Ford 还有其他形式的优化,这些优化在部分图上效果明显,但在某些特殊图上,最坏复杂度可能达到指数级。

    • 堆优化:将队列换成堆,与 Dijkstra 的区别是允许一个点多次入队。在有负权边的图可能被卡成指数级复杂度。
    • 栈优化:将队列换成栈(即将原来的 BFS 过程变成 DFS),在寻找负环时可能具有更高效率,但最坏时间复杂度仍然为指数级。
    • LLL 优化:将普通队列换成双端队列,每次将入队结点距离和队内距离平均值比较,如果更大则插入至队尾,否则插入队首。
    • SLF 优化:将普通队列换成双端队列,每次将入队结点距离和队首比较,如果更大则插入至队尾,否则插入队首。

    更多优化以及针对这些优化的 Hack 方法,可以看 fstqwq 在知乎上的回答

    Raffica 在知乎上的回答 提到了一种很难被卡的 SPFA,大家可以看看

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e4+5,M=5e5+5;
    struct edge {
    	int to,nxt,w;
    } e[M];
    int cnt,head[N];
    int add(int u,int v,int w) {
    	e[++cnt].to=v,e[cnt].w=w,e[cnt].nxt=head[u],head[u]=cnt;
    	return cnt;
    }
    deque<int> q;
    bitset<N> in;
    int dis[N];
    int main() {
    	int n,m,s;
    	scanf("%d %d %d",&n,&m,&s);
    	for(int i=1,u,v,w; i<=m; i++) {
    		scanf("%d %d %d",&u,&v,&w);
    		if(u==v) {
    			continue;
    		}
    		add(u,v,w);
    	}
    	for(int i=1; i<=n; i++) {
    		dis[i]=INT_MAX;
    	}
    	q.push_front(s),in[s]=1,dis[s]=0;
    	while(q.size()) {
    		int u=q.front();
    		q.pop_front(),in[u]=0;
    		for(int i=head[u]; i; i=e[i].nxt) {
    			int v=e[i].to,w=e[i].w;
    			if(dis[u]+w<dis[v]) {
    				dis[v]=dis[u]+w;
    				if(!in[v]) {
    					if(dis[v]>dis[q.front()]) {
    						q.push_back(v);
    					} else {
    						q.push_front(v);
    					}
    					in[v]=1;
    				}
    			}
    		}
    	}
    	for(int i=1; i<s; i++) {
    		printf("%d ",dis[i]);
    	}
    	printf("0 ");
    	for(int i=s+1; i<=n; i++) {
    		printf("%d ",dis[i]);
    	}
    	return 0;
    }
    

    版权说明

    部分来源于 OI-Wiki

  • 相关阅读:
    制作windows服务
    DTCMS部署错误
    mysql常用操作
    eclipse maven jdk全局设置
    linux下安装lnmp环境
    aliyun阿里云Maven仓库地址——加速你的maven构建
    移动端前端框架UI库(Frozen UI、WeUI、SUI Mobile)
    getFields和getDeclaredFields
    2016暑假集训第三次训练赛题解
    HDU5863 cjj's string game(DP + 矩阵快速幂)
  • 原文地址:https://www.cnblogs.com/Sam2007/p/13903831.html
Copyright © 2011-2022 走看看