poj 3259 Bellman_Ford算法 SPFA算法

今天更下负权值的最短路,最短路存在,则图中无回路,环(回路)分为零环,负环,正环,若最短路是零环和正环,则去掉此环肯定小于等于原最短路;若为负环,则无最短路,因为会一直负环下去。

若为经典的无环问题,则算法代码如下:

for(int i=0;i<n;i++)
dis[i]=INF;
d[0]=0;
for(int k=0;k<n-1;k++)//共n-1次,也就是除了起始点以外的点 
for(int i=0;i<m;i++){//检查没个边 
	int x=u[i],y=v[i];
	if(d[x]<INF) d[y]=min(d[y],d[x]+w[i])//松弛 
} 

时间复杂度为n*m当然可以优化,下面给出本题题目;

题目链接:http://poj.org/problem?id=3259

题意(这个是copy的。。)

农夫约翰在探索他的许多农场,发现了一些惊人的虫洞。虫洞是很奇特的,因为它是一个单向通道,可让你进入虫洞的前达到目的地!他的N(1≤N≤500)个农场被编号为1..N,之间有M(1≤M≤2500)条路径,W(1≤W≤200)个虫洞。FJ作为一个狂热的时间旅行的爱好者,他要做到以下几点:开始在一个区域,通过一些路径和虫洞旅行,他要回到最开时出发的那个区域出发前的时间。也许他就能遇到自己了:)。为了帮助FJ找出这是否是可以或不可以,他会为你提供F个农场的完整的映射到(1≤F≤5)。所有的路径所花时间都不大于10000秒,所有的虫洞都不大于万秒的时间回溯。

题目要求:求有无负环,任意点有负环则最终时间能小于开始时间(一直走负环就可以了),下面给出用FIFO队列(SPFA算法)(最坏的情况时间复杂度为n*m,发现负环及时退出)的代码:

#include<iostream>
#include<vector>
#include<queue> 
#include<cstdio>
using namespace std;
struct E{
	int to, dist;
	E() {};
	E(int to, int dist) : to(to), dist(dist){};//构造 
};
int N,M,W;
vector<vector<E> >G;//邻接表 
vector<int> dis;//每个点的最短距离 
vector<bool> bUsed;//用bool数组记录每个点是否在队列中
//vector<int> q;  //这个是最短路径中的一条弧,本题不用,但是还是写下。 
vector<int>cnt;//每个点进入队列的次数 
const int INF = 2e9;//无穷大 
bool BF(int s){//Ballman_Ford 
     queue<int> Q;//队列优化 
     cnt.clear(), cnt.resize(N+1,0);//初始化 
     dis.clear(), dis.resize(N+1,INF);
     //q.clear(),q.resize(N+1,INF);
     bUsed.clear(), bUsed.resize(N+1, false);
     dis[s]=0,bUsed[s] = true, Q.push(s);//带入起始点 
     while(! Q.empty()){//用队列来代替n-1次的循环检查 
     	int u = Q.front(); Q.pop();//队列首,也就是上个邻接的点 
     	bUsed[u] = false;//因为存在负权,所以要再次判断 
     	for(int i = 0; i <G [u].size(); i ++){//此点的每个邻接点 
     		E e= G [u][i];
     		if(dis[u] < INF && dis[e.to] > dis[u] + e.dist){//若接上比原路径要小 
     			dis[e.to] = dis[u] + e.dist;
     		//	q[u]=e.to;
     			if(! bUsed[e.to]){//若下个点此次还没走过 
     				Q.push(e.to), bUsed[e.to] = true;//将下个点入队 
     				if(++ cnt[e.to] >= N)//如果一个点入队的次数大于等于n,则必有负环 
     				return true;//本题需要有负环 
				 }
			 }
		 }
	 }
     return false;
}
int main(){
	int F;
	scanf("%d",&F);
	while(F--){//构造图 
		scanf("%d%d%d", &N, &M, &W);
		G.clear(), G.resize(N+1);
		while(M --){
			int s, e, t;
			scanf("%d%d%d",&s, &e, &t);
			G[s].push_back(E(e,t));
			G[e].push_back(E(s,t));
		}
		while(W --){
			int s,e,t;
			scanf("%d%d%d",&s, &e, &t);
			t *= -1;
			G[s].push_back(E(e,t));
		}
		if( BF(1) ) cout<<"YES"<<endl;
		else cout<<"NO"<<endl;
	}
	return 0;
} 

最后:

programming is the most fun you can have with your clothes on.

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