单源最短路径 Bellman-Ford----解决负权变(加入了队列优化)

算法过程

初始时将源点加入队列,每次从队首取出一个定点,并与其出边进行松弛操作,如果松弛成功则将该出边的终点加入到队列中去,处理完毕该点的所有出边后,出队列,继续进行上述操作,选取队列的顶点,直到队列为空,算法结束,这里需要用一个book数组进行记录目前队列中存在哪些点,如果对某一条边松弛成功,但是该出边的终点在队列中,那么久没必要把该点插入到队列中,因为队列中存在该点,会对该点的说=所有出边进行松弛操作,通过队列优化的Bellman-ford算法如何判断一个图是否存在负环(这里一开始对负环的理解出现了错误,导致一直不理解如何判断存在负环,负环指的是整个环的的权值之和为负值,而不是存在着权值为负值的边的环,- -…)?如果某个点进入队列的次数超过n次,那么这个图则肯定存在负环

用队列优化的Bellman-ford=算法的关键之处在于:只有那些在前一遍松弛中改变了最短路径估计值的点,才可能在引起他们邻接点最短路径的估计值发生变化

该算法的时间复杂度在最坏的情况下也是O(NM)

#include<iostream>
#include<cstring>
#include<string>    
#include<queue>    
#include<algorithm>        
#include<map>    
#include<iomanip>    
#define inf 0x3f3f3f3f    
#define maxn 20   
using namespace std;     //求的是顶点1到其余各顶点的最短路径 
int  head[maxn];
int n,m;
struct node{
	int front,to,w,next;
};
node edge[maxn];
int book[maxn];//标记哪些点已经在队列中 
int dis[maxn];
int temp[maxn];//用来存放同一个顶点进入队列的次数 
queue<int> q;

int main()
{
	int flag=0;
	scanf("%d%d",&n,&m);
	memset(head,-1,sizeof(head));
	//有向图 ,邻接表的建立 
	for(int i=0;i<m;i++)
	{
		scanf("%d%d%d",&edge[i].front,&edge[i].to,&edge[i].w);
		edge[i].next=head[edge[i].front];
		head[edge[i].front]=i;
	}
	//dis数组的初始化
	dis[1]=0;
	for(int i=2;i<=n;i++)
		dis[i]=inf; 
	q.push(1);//源点进去队列 
	book[1]=1;//源点被标记 
	temp[1]++;//源点进入队列的次数加一 
	while(!q.empty())//判断队列是否为空 
	{
		int k=head[q.front()];//选择队列的顶点 
		while(k!=-1)//对队列顶点的出边进行松弛操作 
		{
			if(dis[edge[k].to]>dis[edge[k].front]+edge[k].w)
			{
				dis[edge[k].to]=dis[edge[k].front]+edge[k].w;
				if(book[edge[k].to]==0)//如果没在队列中们就插入到队尾 
				{
					q.push(edge[k].to);
					book[edge[k].to]=1;//进入对了,就标记为1 
					temp[edge[k].to]++;//同时改点的进入队列的次数加一 
					if(temp[edge[k].to]>n)//判断是否存在进入队列超过n次的点,存在的话就存在负环,不会出现最短路径 
					{
						flag=1;//用来跳出两个while循环 
						break;
					}
				}
			}
			k=edge[k].next;
		}
		if(flag)
			break;
		book[q.front()]=0;//出队列后取消标记,因为同一点可能会多次进入队列 
		q.pop();//顶点出队列 
		
	}
	
	if(flag)//flag为1,则存在负权回路 
		printf("存在负权回路\n");
	else
	{
	    //不存在负权回路,打印顶点1到其他顶点的最短路径 
		for(int i=1;i<=n;i++)
			printf("%d ",dis[i]);
		printf("\n");	
	} 
	return 0;
}
/*
输入数据
Input 1: 
5 7
1 2 2
1 5 10
2 3 3
2 5 7
3 4 4
4 5 5
5 3 6

Input 2:
3 3 
1 2 1
2 3 2
3 1 -3

Input 3:
3 3 
1 2 1
2 3 2
3 1 -4

输出结果
Output 1:
0 2 5 9 9 

Output 2:
0 1 3

Output 3:
存在负权回路 
*/
    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/Haskei/article/details/53150961
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞