ACM: POJ 3259 Wormholes - SPFA负环判定
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..N, M (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 of each farm: Three space-separated integers respectively: N, M, and W
Lines 2.. M+1 of each farm: Three space-separated numbers ( S, E, T) 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.. M+ W+1 of each farm: Three space-separated numbers ( S, E, T) that describe, respectively: A one way path from S to E that also moves the traveler back T seconds.
Output
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 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;
}

浙公网安备 33010602011771号