vijos1053 用spfa判断是否存在负环

MARK 用spfa判断是否存在负环

 

判断是否存在负环的方法有很多,

其中用spfa判断的方法是:如果存在一个点入栈两次,那么就存在负环。

细节想想确实是这样,按理来说是不存在入栈两次的如果边权值为正的话

这个算法是O(N*M)

还有一种方法是直接用bellman-ford,虽说spfa也就是bellman-ford+FIFO队列

而且bellman-ford还可以计算负环的值

顺手附上代码好了:

for(int i=0;i<n;i++) d[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]<?=d[x]+w[i];
}

 这一题我是没有用bellman-ford...因为看到有人说用这个超时了= =

 

这里说一下用spfa的做法= =

虽然本蒟蒻第6个点莫名WA,但是毕竟思路还是正确的,自己MARK一下

目测是一些地方没有考虑到吧,据说有重边?有可能是这个?= =懒得管了

 

其实就是每个点都spfa一遍,看是否存在负环;

如果不存在的的话,就输出s-这些点的距离

 

至于spfa里面,其实也很简单,就是

	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=false;
		for(int i=head[u];i!=-1;i=e[i].next){
			int v=e[i].to;
			if(dist[v]>dist[u]+e[i].w){
				dist[v]=dist[u]+e[i].w;
				if(!vis[v]){
					vis[v]=true;
					q.push(v);
					if(ans[v]<2){//这里用数组ans记录下,v这个点入栈几次
						ans[v]++;
					}
					else return true;
				}
			}
		}
	}

 

附上完整代码:

#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
using namespace std;
const int maxn=101000;
int n,m,k,t,x,y,s,z,tot=0;
struct edge{
	int from,to,w,next;
}e[1010000];
int head[maxn],dist[maxn],ans[maxn];
bool vis[maxn];
int f[maxn];
bool flag;
void add(int x,int y,int z){
	e[tot].from=x;
	e[tot].to=y;
	e[tot].w=z;
	e[tot].next=head[x];
	head[x]=tot++;
}
bool spfa(int s){
	queue<int>q;
	memset(dist,63,sizeof(dist));
	memset(vis,false,sizeof(vis));
	memset(ans,0,sizeof(ans));
	q.push(s);
	dist[s]=0;
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=false;
		for(int i=head[u];i!=-1;i=e[i].next){
			int v=e[i].to;
			if(dist[v]>dist[u]+e[i].w){
				dist[v]=dist[u]+e[i].w;
				if(!vis[v]){
					vis[v]=true;
					q.push(v);
					if(ans[v]<2){
						ans[v]++;
					}
					else return true;
				}
			}
		}
	}
	return false;
}
int main(){
	freopen("data.txt","r",stdin);
	scanf("%d%d%d",&n,&m,&s);
	memset(head,-1,sizeof(head));
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&x,&y,&z);
		add(x,y,z);
		if(x==y && z<0){
			printf("-1\n");
			return 0;
		}
	}	
    for(int i=1;i<=n;i++){
    	if(spfa(i)){
    		printf("-1\n");
    		return 0;
    	}
    }
    spfa(s);
    for(int i=1;i<=n;i++){
    	if(dist[i]>1000000){
    		if(i!=s) printf("NoPath\n");
    		else printf("0\n");
    	}
    	else printf("%d\n",dist[i]);
    }
    return 0;
}

 

posted @ 2014-08-12 17:28  polebug  阅读(381)  评论(0编辑  收藏  举报