spfa求最短路

本文探讨了如何通过队列优化Bellman-Ford算法,减少无效边的遍历,并介绍了SPFA算法及其与Dijkstra算法的区别,重点在于SPFA在处理负权回路时的注意事项。此外,文章还讲解了如何利用计数数组检测负环的存在。
摘要由CSDN通过智能技术生成

Bellman_ford算法会遍历所有的边,但是有很多的边遍历了其实没有什么意义,我们只用遍历那些到源点距离变小的点所连接的边即可,只有当一个点的前驱结点更新了,该节点才会得到更新;因此考虑到这一点,我们将创建一个队列每一次加入距离被更新的结点。

注意

1、vis并不是标记一下是否使用 而是标记是否可以再次压入queue
2、跟堆优化Dijstra很像,但是完全不同。
3、Bellman_ford算法最后是用 dis[n] > inf/2 来判断而spfa是用 dis[n] == inf 判断 是因为bellman_ford会遍历每一个点,所以 n 点值会发生变化 而spfa每次都更新连通的源点之间距离,如果不连通是不会影响到 dis[n] 的。
4、Bellman_ford算法可以存在负权回路,是因为其循环的次数是有限制的因此最终不会发生死循环;但是SPFA算法不可以,由于用了队列来存储,只要发生了更新就会不断的入队,因此假如有负权回路就不要用SPFA,否则会死循环。
5、由于SPFA算法是由Bellman_ford算法优化而来,在最坏的情况下时间复杂度和它一样即时间复杂度为 O(nm)O(nm) ,假如题目时间允许可以直接用SPFA算法去解Dijkstra算法的题目。
6、求负环一般使用SPFA算法,方法是用一个cnt数组记录每个点到源点的边数,一个点被更新一次就+1,一旦有点的边数达到了n那就证明存在了负环。
在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
const int maxn = 1e5+10;
const int inf  = 0x3f3f3f3f;
queue<PII> q ;
int w[maxn],to[maxn],vis[maxn],nex[maxn],now[maxn],dis[maxn];
//  权值	边终点	标记	   同一起点的  目前编号  到达每一点
//							   另一边编号 			 的最小距离 
int idx,n,m;
void add(int x,int y,int z){
	to [idx] = y;
	w  [idx] = z;
	nex[idx] = now[x];
	now[x]      = idx++;
}
int di(){
	q.push({0,1});			//压入  距离0 端点1 
	dis[1] = 0;				//起点1 距离0 
	vis[1] = 1;
	while(!q.empty()){
		PII k = q.front();
		q.pop();
		int distance = k.first , ver = k.second;
		vis[ver] = 0;
		for(int i = now[ver]; i != -1 ; i = nex[i]){ //同起点 不同边 
			int j = to[i];				
			if(dis[j] > dis[ver] + w[i]){
				dis[j] = dis[ver] + w[i];
				if(!vis[j]){
					vis[j]=1;
					q.push({dis[j],j});
				}
				
			}
		}
	}
	if(dis[n]==inf) cout<<"impossible";
	else cout<<dis[n];
}
int main(){
	fill(now,now+maxn,-1);
	fill(dis,dis+maxn,inf);
	cin>>n>>m;
	for(int i = 0 ;i < m; i++){
		int x,y,z;
		cin>>x>>y>>z;
		add(x,y,z);
	}
	di();
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楠风丶北枝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值