[spfa+判负环]poj3259 Wormholes

来源:互联网 发布:莱斯特城奇迹 知乎 编辑:程序博客网 时间:2024/05/16 04:48

Wormholes
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 44542 Accepted: 16390

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..M+W+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

23 3 11 2 21 3 42 3 13 1 33 2 11 2 32 3 43 1 8

Sample Output

NOYES

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.

Source

USACO 2006 December Gold


题意:

题意比较模糊,翻译过来明确一下。

农民John到农场的时候,发现了一些神奇的虫洞。这个虫洞非常古怪,每一个都会把人单向传送到它的目的地且传送后时间是你进入虫洞前的某个时间点(也就是说时间倒流了)。Jonh (1 ≤ N ≤ 500)有F个农场(也就是F个样例),每个农场有N块地,为了方便编号为1..N,M (1 ≤ M ≤ 2500) 条路,和 W (1 ≤ W ≤ 200)个虫洞。

John是个时空旅行的狂热者,为了体验空间转移和时间倒流的奇妙,他想选定某块地,经过一些路和虫洞,再回到起点时时间倒流了,他很想亲身体验这点。

John想请你告诉他是否能实现时间倒流,他会告诉你农场数F (1 ≤ F ≤ 5) 。没有路径将超过10000秒钟,没有虫洞可以把FJ带回10000秒前。(没啥用,就是给出限制条件,给的途径虫洞的时间不超过10000秒)。

输入:输入一个整数F,F个农场(测试样例);接下来输入三个整数N,M,W,N块地,M条普通的路,W条虫洞的路;接下来输入M行,每行三个数字S,E,T,从S地到E地用T秒,注意是双向的,而且会有重边(Two fields might be connected by more than one path.);接下来输入W行,每行三个数字S,E,T,从S地到E地用-T秒(也就是回到T秒前)

输出:能实现时间倒流就输出“YES”,否则输出“NO”;


简单来说就是,一个农民有农场,上面有一些虫洞和路,走虫洞可以回到 T秒前,而路就和平常的一样啦,需要花费时间走过。问该农民可不可能从某个点出发后回到该点,并且于出发时间之前?


思路:

这道题有一些值得我们注意的

1、本题给的N、M范围是没错的,N∈[1,500], M∈[1,5200] (2500*2+200);

2、普通的路(path)是双向的且有重边,虫洞的路(wormhole)是单向的;

3、源点不确定

本题spfa(邻接表)+判负环就可以了,如果一个点入队次数超过n,那么就存在回路。因为spfa求最短路,如果存在环就会一直入队出队,因为有负权所以入队出队过程会一直小,就无限循环啦,正环只会走一次。

数据比较水,我写的代码感觉有漏洞……

比如这两个样例:

2
4 1 3
1 4 200
1 2 1
2 3 1
3 2 1

--------
4 1 3
1 4 200
2 1 1
2 3 1
3 2 1

代码:

#include <iostream>#include <cstdio>#include <algorithm>#include <cmath>#include <string.h>#include <queue>/*spfa+判负环/bellman-fordpath是双向的,wormhole是单向的判断是否有负环即可,有负环输出YES,否则NON: 500M: 2500*2+200 = 5200*/#define N 600#define M 6000#define inf 0x7fffffffusing namespace std;struct node{    int v;    int c;    int next;}edge[M];int path[M];//注意范围int len = 0;int dis[N];bool vis[N];int judge[N];//判断负环int t, n, m, w;void add(int a, int b, int c){    edge[len].v = b;    edge[len].c = c;    edge[len].next = path[a];    path[a] = len++;}bool spfa(){    queue<int>Q;    dis[1] = 0;    Q.push(1);    while(!Q.empty()){        int t = Q.front();        vis[t] = false;        Q.pop();        //判负环        judge[t]++;        if(judge[t] >= n)            return true;        for(int i = path[t]; i != -1; i = edge[i].next){            int w = edge[i].c;            int temp = edge[i].v;            if(dis[temp] > dis[t] + w){                dis[temp] = dis[t] + w;                if(!vis[temp]){                    Q.push(temp);                    vis[temp] = true;                }            }        }    }    return false;}int main(){    int a, b, c;    scanf("%d", &t);    while(t-->0){        len = 0;//注意初始化!!RE很多次        memset(path, -1, sizeof(path));        memset(vis, false, sizeof(vis));        fill(dis, dis+N, inf);        fill(judge, judge+N, 0);        scanf("%d%d%d", &n, &m, &w);        while(m-->0){            scanf("%d%d%d", &a, &b, &c);            add(a, b, c);            add(b, a, c);        }        while(w-->0){            scanf("%d%d%d", &a, &b, &c);            add(a, b, -c);//注意是负权        }        if(spfa())            printf("YES\n");        else            printf("NO\n");    }    return 0;}


反思:

浪费一上午时间,还是细节出了问题:

1、path[]数组的范围,应该和结构体edge[]范围一样的;

2、len忘记初始化,RE了6次,然后上网找了个AC代码才比照出来,我都不好意思说了……

3、注意虫洞路径是负权,add是值是负的

0 0
原创粉丝点击