ACM: POJ 3259 Wormholes - SPFA负环判定

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;
}

  

时间: 2024-10-04 21:28:24

ACM: POJ 3259 Wormholes - SPFA负环判定的相关文章

POJ #3259 Wormholes 判负环

Description 问题描述:链接 思路 裸题,判断图是否有负环,用 bellman_ford 或者 spfa . #include<iostream> #include<algorithm> #include<vector> #include<queue> #include<cstring> using namespace std; #define INF 0x3f3f3f3f int N, M, W; //顶点数 正环数 负权边数 con

[ACM] POJ 3259 Wormholes (bellman-ford最短路径,判断是否存在负权回路)

Wormholes Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 29971   Accepted: 10844 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 p

POJ 3259 Wormholes SPFA算法题解

本题其实也可以使用SPFA算法来求解的,不过就一个关键点,就是当某个顶点入列的次数超过所有顶点的总数的时候,就可以判断是有负环出现了. SPFA原来也是可以处理负环的. 不过SPFA这种处理负环的方法自然比一般的Bellman Ford算法要慢点了. #include <stdio.h> #include <string.h> #include <limits.h> const int MAX_N = 501; const int MAX_M = 2501; const

POJ 3259 Wormholes(SPFA判负环)

题目链接:http://poj.org/problem?id=3259 题目大意是给你n个点,m条双向边,w条负权单向边.问你是否有负环(虫洞). 这个就是spfa判负环的模版题,中间的cnt数组就是记录这个点松弛进队的次数,次数超过点的个数的话,就说明存在负环使其不断松弛. 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <queue> 5 using na

poj 3259 Wormholes spfa : 双端队列优化 判负环 O(k*E)

1 /** 2 problem: http://poj.org/problem?id=3259 3 spfa判负环: 4 当有个点被松弛了n次,则这个点必定为负环中的一个点(n为点的个数) 5 spfa双端队列优化: 6 维护队列使其dist小的点优先处理 7 **/ 8 #include<stdio.h> 9 #include<deque> 10 #include<algorithm> 11 using namespace std; 12 13 class Graph

poj 3259 Wormholes (负权最短路,SPAF)

Wormholes Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 36641   Accepted: 13405 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 p

poj 3259 Wormholes 判断负权值回路

Wormholes Time Limit: 2000 MS Memory Limit: 65536 KB 64-bit integer IO format: %I64d , %I64u   Java class name: Main [Submit] [Status] [Discuss] Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A w

poj 3259 Wormholes(spfa)

#include<stdio.h> #include<queue> #include<string.h> #include<algorithm> using namespace std; const int inf=0x3f3f3f3f; const int N=1024; struct node { int to; int w; node *next; }; node* edge[N]; int n,m,w,cnt[N],vis[N],dist[N]; q

Poj 3259 Wormholes 负环判断 SPFA &amp; BellmanFord

#include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <