Spfa+STL

#include<cstdio>
#include<vector>
#include<deque>  //双向队列  push_back()  push_front()等 
#define MAXV 10000
#define INF 1000000000 //此处建议不要过大或过小,过大易导致运算时溢出,过小可能会被判定为真正的距离
 using namespace std;
struct Edge{
	int v; //边权
	int to; //连接的点
};
vector<Edge> e[MAXV]; //由于一般情况下E<<V*V,故在此选用了vector动态数组存储,也可以使用链表存储
int dist[MAXV]; //存储到原点0的距离,可以开二维数组存储每对节点之间的距离
int cnt[MAXV]; //记录入队次数,超过V则退出
deque<int> buff; //队列,用于存储在SPFA算法中的需要松弛的节点
bool done[MAXV]; //用于判断该节点是否已经在队列中
int V; //节点数
int E; //边数
 
bool spfa(const int st){ //返回值:TRUE为找到最短路返回,FALSE表示出现负环退出
	for(int i=0;i<V;i++){ //初始化:将除了原点st的距离外的所有点到st的距离均赋上一个极大值
		if(i==st){
			dist[st]=0; //原点距离为0;
			continue;
		}
		dist[i]=INF; //非原点距离无穷大
	}
	buff.push_back(st); //原点入队
	done[st]=1; //标记原点已经入队
	cnt[st]=1; //修改入队次数为1
	while(!buff.empty()){ //队列非空,需要继续松弛
		int tmp=buff.front(); //取出队首元素
		buff.pop_front();//弹出队首节点
		for(int i=0;i<(int)e[tmp].size();i++){ //枚举该边连接的每一条边
			Edge *t=&e[tmp][i]; //由于vector的寻址速度较慢,故在此进行一次优化
			if(dist[tmp]+(*t).v<dist[(*t).to]){ //更改后距离更短,进行松弛操作
				dist[(*t).to]=dist[tmp]+(*t).v; //更改边权值
				if(!done[(*t).to]){ //没有入队,则将其入队
			if(!buff.empty()){
				//注意这里比较的是front tmp已经出队了 
				if(dist[(*t).to]>dist[buff.front()])
					buff.push_back((*t).to); //将节点压入队列
					else
					buff.push_front((*t).to);
					}
					else
					buff.push_front((*t).to);	 
					done[(*t).to]=1; //标记节点已经入队
					cnt[(*t).to]+=1; //节点入队次数自增
					if(cnt[(*t).to]>V){ //已经超过V次,出现负环
						while(!buff.empty())buff.pop_front(); //清空队列,释放内存
						return false; //返回FALSE
					}
				}
			}
		}
		//之前的tmo刚出队  执行完前面才取消标记 
		done[tmp]=0;//将队首节点标记为未入队
	}
	return true; //返回TRUE
} //算法结束
 
int main(){ //主函数
	while(scanf("%d%d",&V,&E)==2) {//读入点数和边数
	   for(int i=1;i<=V;i++){  //初始化 
	   	cnt[i]=0;
	    done[i]=0;
	    e[i].clear(); //清空vector数组 
	   }
	for(int i=0,x,y,l;i<E;i++){
		scanf("%d%d%d",&x,&y,&l); //读入x,y,l表示从x->y有一条有向边长度为l
		Edge tmp; //设置一个临时变量,以便存入vector
		tmp.v=l; //设置边权
		tmp.to=y; //设置连接节点
		e[x].push_back(tmp); //将这条边压入x的表中
	}
	//输入源点 
	if(!spfa(1)){ //出现负环
		printf("出现负环,最短路不存在\n");
	}else{ //存在最短路
		for(int i=1;i<=V;i++)
		printf("%d\n",dist[i]); 
	}
}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值