ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

SPFA 的两种优化

2021-11-01 09:32:06  阅读:202  来源: 互联网

标签:两种 队列 入队 SPFA front 优化 dis


SPFA 优化

众所周知,SPFA 它死了

但有些时候你会嫌支持负边的 dijkstra 麻烦,于是不得不选择 SPFA

那么,你需要 SPFA 优化!

SLF 优化

我们可以参考一下 dijkstra 的思路。

dijkstra 每次取队列中的最小值,减少了同一节点入队次数和更新 dis 次数,于是避免了死亡

那么我们感性理解一下,如果我们在 SPFA 中每次也取较小 dis 的点是不是也可以得到一定的优化呢?

我们可以通过双端队列,在节点入队时实现这一点:把需要入队的点的 dis 与队首的比较一下,如果小于队首则将节点从队首入队,否则从队尾入队。

LLL 优化

其实本质原理与 SLF 一样,只是实现方式不同啦 ~

同样使用双端队列,我们额外维护一下队列中所有点的 dis 的平均值,把即将入队的点与这个平均值比较,决定从队首还是队尾入队。

贴(伪)代码

显而易见,这两个优化并不相矛盾,所以我们可以同时使用!

int dis[N];
//起点是 S
inline void SPFA(int S)
{
    //下面这三个东西只在该函数中使用,于是把它们放入函数里,避免被外界调用,不易重名、出错
	static deque<int> q;//双端队列
	static bool inque[N];//记录每个点是否在队列中
	static int sum = 0;//因为平均数不方便维护,我们选择维护队列中 dis 的和
	//TODO: 此处应初始化 dis 数组为 inf
	dis[S] = 0;
	q.push_back(S);
	while (q.size()) {
		int x = q.front();
		q.pop_front();
		inque[x] = 0, sum -= dis[x];//出队维护qaq
		for (/*TODO: 遍历 x 的所有出边: 出边 e 和 对应点 y  */) {
			if (dis[y] > dis[x] + w[e]) {
				dis[y] = dis[x] + w[e];
				if (!inque[y]) {
//此处为两种优化的核心
                    //一定要注意队列为空的特殊情况
					if (q.empty() || dis[y] < dis[q.front()] || dis[y]*q.size() < sum)
						q.push_front(y);
					else q.push_back(y);
//
					inque[y] = 1, sum += dis[y];//入队记得维护qwq
				}
			}
		}
	}
}

十分简单好写呢,为什么不随手写一个呢

注意:LLL 有时可能因为常数问题导致负优化

标签:两种,队列,入队,SPFA,front,优化,dis
来源: https://www.cnblogs.com/gyan083/p/15492061.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有