码迷,mamicode.com
首页 > 其他好文 > 详细

ACM: POJ 3259 Wormholes - SPFA负环判定

时间:2016-08-12 00:39:53      阅读:577      评论:0      收藏:0      [点我收藏+]

标签:

 POJ 3259 Wormholes
Time Limit:2000MS     Memory Limit:65536KB     64bit IO Format:%lld & %llu
 

Description

While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wormhole! Each of FJ‘s farms comprises N (1 ≤ N ≤ 500) fields conveniently numbered 1..NM (1 ≤ M ≤ 2500) paths, and W (1 ≤ W ≤ 200) wormholes.

As FJ is an avid time-traveling fan, he wants to do the following: start at some field, travel through some paths and wormholes, and return to the starting field a time before his initial departure. Perhaps he will be able to meet himself :) .

To help FJ find out whether this is possible or not, he will supply you with complete maps to F (1 ≤ F ≤ 5) of his farms. No paths will take longer than 10,000 seconds to travel and no wormhole can bring FJ back in time by more than 10,000 seconds.

Input

Line 1: A single integer, FF farm descriptions follow. 
Line 1 of each farm: Three space-separated integers respectively: NM, and W 
Lines 2.. M+1 of each farm: Three space-separated numbers ( SET) that describe, respectively: a bidirectional path between S and E that requires T seconds to traverse. Two fields might be connected by more than one path. 
Lines M+2.. MW+1 of each farm: Three space-separated numbers ( SET) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.

Output

Lines 1.. F: For each farm, output "YES" if FJ can achieve his goal, otherwise output "NO" (do not include the quotes).

Sample Input

2
3 3 1
1 2 2
1 3 4
2 3 1
3 1 3
3 2 1
1 2 3
2 3 4
3 1 8

Sample Output

NO
YES

Hint

For farm 1, FJ cannot travel back in time. 
For farm 2, FJ could travel back in time by the cycle 1->2->3->1, arriving back at his starting location 1 second before he leaves. He could start from anywhere on the cycle to accomplish this.
 
/*/
这题是判断是否产生了负环。

由于边权出现了负数这个题目就不能用普通的最短路来算,用到Floyd 或者SPFA算法。

由于题目意思要判断是否产生了负环,可以直接用SPFA算法来判断负环。

下面这个SPFA算法,d[n]为终点,如果起点u开始到达不了某个点,那么d等于INF 

如果到达的了,且路上会经过负环,所以到达那个点的时候,最短路会等于-INF

如果到达那个点的时候,是正常到达的,没有经过负环,而且可以到达,那么就是介于两者之间的一个正常的值。

AC代码:

/*/

 

 
#include"algorithm"
#include"iostream"
#include"cstring"
#include"cstdlib"
#include"cstdio"
#include"string"
#include"vector"
#include"queue"
#include"cmath"
using namespace std;
typedef long long LL ;
#define memset(x,y) memset(x,y,sizeof(x))
#define memcpy(x,y) memcpy(x,y,sizeof(x))
#define FK(x) cout<<"["<<x<<"]\n"
#define bigfor(x) for(int qq=1;qq<= T ;qq++)

const int spfa_v=10005;
const int spfa_edge=10005;

template <class T>
struct SPFA {

	struct Edge {
		int v,nxt;
		T w;
	} E[spfa_edge<<1];

	int Head[spfa_v],erear;

	T p[spfa_v],INF;

	typedef pair< T , int > PII;

	void edge_init() {
		memset(Head,-1);
		memset(E,0);
		memset(dis,0);
		erear=0;
	}

	void edge_add(int u,int v,T w) {
		E[erear].v=v;
		E[erear].w=w;
		E[erear].nxt=Head[u];
		Head[u]=erear++;
	}

	bool dis[spfa_edge];
	bool vis[spfa_edge];
	int flag[spfa_edge];

	void init() {
		memset(vis,0);
		memset(p,0x3f);
		memset(flag,0);
		memset(dis,0);
		INF=p[0];
	}

	void run(int u,int n) { //u为起点
		init();
		queue<int > Q;
		while(!Q.empty())Q.pop();
		p[u]=0;
		Q.push(u);
		while(!Q.empty()) {
			int a=Q.front();
			Q.pop();
			vis[a]=0,dis[a]=1;
			for(int i=Head[a]; ~i; i=E[i].nxt) {
				int v=E[i].v;
				T   w=E[i].w;
				int s = p[a] == -INF?-INF:w+p[a];  //如果已经是负环了,后面的也赋值-INF
				if(s<p[v]) {
					p[v]=s;
					if(!vis[v]) {  //判断是否已经走过这条边了。
						vis[v]=1;
						flag[v]++;
						if(flag[v]>n)p[v]=-INF; //如果超过n次则说明已经形成了负环,值赋为-INF
						Q.push(v);
					}
				}
			}
		}
	}
};
SPFA<int > sp;


int main() {
	int T;
	int n,m,k,u,v,w;
	while(~scanf("%d",&T)) {
		bigfor(T) {
			sp.edge_init();
			int sign=0;
			scanf("%d%d%d",&n,&m,&k);
			for(int i=0; i<m; i++) {
				scanf("%d%d%d",&u,&v,&w);
				sp.edge_add(u,v,w);
				sp.edge_add(v,u,w);
			}
			for(int i=0; i<k; i++) {
				scanf("%d%d%d",&u,&v,&w);
				sp.edge_add(u,v,-w);
			}
			for(int i=1; i<=n; i++) {
				if(sp.dis[i])continue; //如果这个点已经查过那就不需要再查。
				sp.run(i,n);
				if(sp.p[i]<0) {//产生了负环sp.p[i]的值才可能为负 而且是 -INF 
sign=1;break; } } printf("%s\n",sign?"YES":"NO") ; } } return 0; }

  

 

ACM: POJ 3259 Wormholes - SPFA负环判定

标签:

原文地址:http://www.cnblogs.com/HDMaxfun/p/5762991.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!