spfa比bellman的优化

   bellman算法相对dijkstra能对负环进行判断,dijkstra因为算法应用了贪心思路,会对走过的点进行标记不走回头路,所以面对负环时会无法算出最短值如A->B为2,A->C为1,C->B为-1,A到B最短值为0,但因为dijkstra会先从A到B最后结果为2与实际不符,这时人们发明了bellman算法。

#include<bits/stdc++.h>
#define LL long long 
using namespace std;

const int N=5e5+7;
int mod=100003;
LL vis[N];
LL d[N];//记录用n条边能 
struct Edge{
	int to,next,val;
}edge[N];
int head[N];
int cnt=0;
void addedge(int b,int e,int val)
{
	cnt++;
	edge[cnt].to=e;
	edge[cnt].next=head[b];
	edge[cnt].val=val;
	head[b]=cnt;
} 	int n,m,s;
//dp思路,每一次从上一次做完的继承下来,每n次代表走n次能到点的最大值 
bool bellman_ford(int x)
{

	for(int i=1;i<=n;i++) d[i]=pow(2,31)-1;	d[x]=0;
	bool flag;
	for(int i=1;i<=n;i++)//i是次数,做了几次 
	{
		flag=false;
		for(int k=1;k<=n;k++) 
		{
			for(int j=head[k];j;j=edge[j].next)
			{//遍历每一个点 
		        if(d[edge[j].to]>edge[j].val+d[k])//松驰 
		      {
			d[edge[j].to]=edge[j].val+d[k];
		    flag=true;
		      }
			}
	
		}
		
		if(!flag)break;
	}
		if(flag) return false;
	else return true;
}
int main()
{

	cin>>n>>m>>s;
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		cin>>u>>v>>w;
		addedge(u,v,w);
	}
	bellman_ford(s);
	for(int i=1;i<=n;i++)cout<<d[i]<<" ";
	return 0;
}

bellman算法的思路是重复n次,每次便利n条边最后求的最短值。

这里挂个链接方便理解贝尔曼福特算法说人话版(Bellman-Ford)_哔哩哔哩_bilibili

同时在视频中我们发现已近确定的边依然会被遍历,在bellman算法下我们可以当便利所有边是最小值都不会改变是break,来减少复杂度。同时我们也可以利用spfa算法来进行优化。

#include<iostream>
#include<bits/stdc++.h>
#include<fstream>
#include<vector>
#include<cstring>
#include<queue>

using namespace std;
struct E
{
	int to,v;
}e;
vector<E> G[20001];

long long n,m,I,cost[10001];
bool visit[10005];

bool SPFA()
{
	long h=0,t=1;
	queue<int> q;
	for(long i=1;i<=n;i++) cost[i]=0x3f3f3f3f;
 	cost[I]=0;
 	q.push(I);
 	memset(visit,0,sizeof(visit));
	while(!q.empty())
 	{
		int t=q.front();
 		for(int i=0; i<G[t].size(); i++)
 		if(cost[G[t][i].to]> cost[t]+ G[t][i].v)
 		{
 			cost[G[t][i].to]=cost[t]+ G[t][i].v;
		
		
 			if (!visit[G[t][i].to])
			{
 				q.push(G[t][i].to);
				visit[G[t][i].to]=1;
 			} 
 		} 
 		visit[t]=0;
		q.pop(); 
	}
	return true;
}

void init()
{
	cin>>n>>m>>I;
	int x;
	for(int i=1;i<=m;i++)
	{
		cin>>x>>e.to>>e.v;
		G[x].push_back(e);
	}
	SPFA();
	for(int i=1;i<=n;i++) 	 
	if(cost[i]==0x3f3f3f3f)cout<<"2147483647 ";
	    else cout<<cost[i]<<' ';
}
int main()
{
	init();
	return 0;
}

spfa算法利用一个队列(不是dijkstra的优先队列)对要走的边加入队列,已近确定的不再重复计算提高运行效率。需要注意的是是spfa的标记在每次取出是要去除,标记是为了减少不必要的运算,去除是为了避免成为dijkstra。(这段代码我把求负环的删了)

(这篇文章是对我学习的总结,如有问提我会虚心求教,希望大家的指正)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值