Wormholes(spfa判负环)

本文解析了POJ-3259虫洞问题,介绍了如何利用SPFA算法检测图中是否存在负权回路,进而判断是否可以通过虫洞回到过去。并提供了完整的代码实现。

            POJ - 3259—— Wormholes
Time Limit: 2000MS Memory Limit: 65536KB 64bit IO Format: %I64d & %I64u
 use MathJax to parse formulas

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.

在探索他的农场时,农场主约翰发现了一些令人惊叹的虫洞。虫洞是非常独特的,因为它是一条单向路径,在进入虫洞之前,它会把你带到它的目的地。每个FJ农场由N(1≤N≤500)字段方便编号1 . .N,M(1≤≤2500)路径,和W W(1≤≤200)虫洞。

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.

帮助FJ找出是否这是可能的,他将为你提供完整的映射到F(F 1≤≤5)他的农场。没有路径需要超过1万秒的时间来旅行,而且没有虫洞可以让FJ回到1万多秒的时间。

Input

输入

Line 1: A single integer, F. F farm descriptions follow.

第1行:一个单独的整数,F . F农场描述如下。

Line 1 of each farm: Three space-separated integers respectively: N, M, and W

每个农场的第1行:分别是3个空格分隔的整数:N、M和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.

行2 . .每个农场的M + 1:分别描述的三个空格分隔的数字(S,E,T):在S和E之间的双向路径,需要T秒来遍历。两个字段可能由多个路径连接。

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.

行M + 2 . .每个农场的M + W + 1:分别描述的三个空格分隔的数字(S,E,T):一个从S到E的路径,这也使旅行者返回T秒。

Output

输出

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

行1 . .F:对于每个农场,如果FJ能达到他的目标,输出“是”,否则输出“不”(不包括引号)。

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.

对于农场1号来说,FJ不能及时返回。

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.

对于第2个农场,FJ可以在周期1 - > 2 - > 3 - > 1的时间内返回,在他离开之前1秒到达他的起始位置。他可以从这个周期的任何一个地方开始完成这个任务。

 

题意是问是否能通过虫洞回到过去;

虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。

我们把虫洞看成是一条负权路,问题就转化成求一个图中是否存在负权回路;

所以说这个题还是比较水的。

各种错误:

数组开小了!一直RE!

该网站上无返回值的函数必须用void!否则CE。

在spfa里面多加了一个dis[s]=0;WA!

代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 2521
using namespace std;
int t,dis[N],x,y,z,n,m,s,tot,head[N];
bool vis[N],flag;
struct Edge
{
    int to,next,ds;
}edge[N*2];
int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();        
    }
    while(ch<='9'&&ch>='0')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
void add(int from,int to,int dis)
{
    tot++;
    edge[tot].ds=dis;
    edge[tot].to=to;
    edge[tot].next=head[from];
    head[from]=tot;
}
void begin()
{
    memset(dis,0,sizeof(dis));
    memset(vis,false,sizeof(vis));
    memset(head,0,sizeof(head));
    tot=flag=0;
}
void spfa(int s)
{
    vis[s]=true;
//    if(flag) return ;
    for(int i=head[s];i;i=edge[i].next)
    {
        if(dis[s]+edge[i].ds<dis[edge[i].to])
        {
            if(vis[edge[i].to]||flag)
            {
                flag=true;
                break;
            }
            dis[edge[i].to]=dis[s]+edge[i].ds;
            spfa(edge[i].to);
        }
    }
    vis[s]=false;
}
int main()
{
    t=read();
    while(t--)
    {
        n=read(),m=read(),s=read();
        begin();
        for(int i=1;i<=m;i++)
        {
            x=read(),y=read(),z=read();
            add(x,y,z);
            add(y,x,z);
        }
        for(int i=1;i<=s;i++)
        {
            x=read(),y=read(),z=read();
            add(x,y,-z);
        }
        for(int i=1;i<=n;i++)
        {
            spfa(i);
            if(flag) break;
        }
        if(flag) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/z360/p/6884831.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值