LG P2850 [USACO06DEC]蟲洞Wormholes

討論版題面

蟲洞(wormhole)

FJ 在農場上閒逛時,發現他的農場裏有很多蟲洞。蟲洞是一條特殊的有向路徑,當

FJ 從它的一頭走到另一頭後,他將被傳送到過去的某個時刻。FJ 的每個農場包括

N(1<=N<=500)塊按1..N 編號的草地、M(1<=M<=2500)條草地間的道路以及W(1<=W<=200)

個蟲洞。

FJ 一直以來就渴望進行時間旅行,於是他開始做如下的打算:從某塊草地出發,穿

過一些道路以及一些蟲洞,最終回到他出發的草地。這樣,他說不定能碰見過去的自

己:) 。

請你幫FJ 算一下,他是否可能找到這樣的一條路。當然,FJ 會給你他的所有

F(1<=F<=5)個農場的完整的地圖。沒有哪條道路上需要花的時間超過10,000 秒,同時,

也沒有哪個蟲洞能把FJ 帶回10,000 秒以前。

程序名: wormhole

輸入格式:

* 第1 行: 一個正整數F,即農場總數。以下依次描述各個農場的地圖

* 每個農場描述的第1 行:三個用空格隔開的整數,N、M 和W

* 每個農場描述的第2..M+1 行:每行包含三個用空格隔開的整數S、E、T,表示

編號爲S 的草地和編號爲E 的草地邊有一條雙向道路,通過它所花費的時間爲T 秒。兩

塊草地間可能有多條道路

* 每個農場描述的第M+2..M+W+1 行:每行包含三個用空格隔開的整數S、E、T,

描述了一個起點編號爲S、終點編號爲E 的蟲洞。穿過這個蟲洞後,FJ 可以回到T 秒之



輸入樣例(wormhole.in):

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

輸入說明:

FJ 交給你兩個農場的地圖。第一個農場裏有三條道路以及一個蟲洞,第二個農場裏

有兩條道路和一個蟲洞。

輸出格式:

* 第1..F 行: 對於每個農場,如果FJ 可以實現他回到過去的願望,輸出"YES",

否則輸出"NO"(不含引號)。

輸出樣例(wormhole.out):

NO
YES

輸出說明:

在農場1 中,FJ 無法完成他期望的時間旅行。

在農場2 中,FJ 可以沿路線1->2->3->1 旅行,這樣他能在離開1 號草地前一秒回

到1 號草地。當然,從這條路線上的其他草地出發,也能達到目的。



luogu題面

題目描述

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.

John在他的農場中閒逛時發現了許多蟲洞。蟲洞可以看作一條十分奇特的有向邊,並可以使你返回到過去的一個時刻(相對你進入蟲洞之前)。John的每個農場有M條小路(無向邊)連接着N (從1..N標號)塊地,並有W個蟲洞。其中1<=N<=500,1<=M<=2500,1<=W<=200。 現在John想借助這些蟲洞來回到過去(出發時刻之前),請你告訴他能辦到嗎。 John將向你提供F(1<=F<=5)個農場的地圖。沒有小路會耗費你超過10000秒的時間,當然也沒有蟲洞回幫你回到超過10000秒以前。

輸入輸出格式

輸入格式:

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

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.

輸出格式:

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

輸入輸出樣例

輸入樣例#1: 複製
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
輸出樣例#1: 複製
NO
YES

說明

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.



存在負環時就是可以回到過去的情況,那麼題目就轉化成了判斷圖中是否存在負環的一個題目
這個就可以用DFS版的SPFA,但是如果用原來的鬆弛方法很慢,那麼可以加速一下,把所有的距離都設置爲0,這樣就只有有負權邊的時候纔會鬆弛下去,很大程度上加速了運行速度,當然你也可以記錄下所有負權邊的起點,逐個提取跑SPFA,不過我試驗了一下,把距離設置爲0用時和記錄所有負權邊的起點的用時都是0ms,空間上記錄所有負權邊的起點不如距離設置爲0優秀,要多佔用0.05MB

但是憑我只能想到記錄所有負權邊起點。。。

那麼下邊給出所有的距離均設置爲0的寫法

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define For(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
int read()
{
    bool t=0;
    int a=0;
    char c;
    while((c=getchar())==' '||c=='\r'||c=='\n');
    if(c=='-')
    {
        t=1;
        c=getchar();
    }
    while(isdigit(c))
    {
        a*=10;
        a+=c;
        a-='0';
        c=getchar();
    }
    return a*(t?-1:1);
}
struct line{
    int to,next,v;
}edge[5210];
int n,m,w,dis[501],last[501],que[201];
bool vis[501],t;
void setup()
{
    t=0;
    memset(last,0,sizeof last);
}
void dfs(int x)
{
    if(vis[x])
    {
        t=1;
        return;
    }
    vis[x]=1;
    int p=last[x];
    while(p&&!t)
    {
        if(dis[edge[p].to]>edge[p].v+dis[x])
        {
         dis[edge[p].to]=edge[p].v+dis[x];
         dfs(edge[p].to);
        }
        p=edge[p].next;
    }
    vis[x]=0;
}
void spfa(int s)
{
    memset(dis,0,sizeof dis);
    dfs(s);
}
void add(int from,int to,int v,int i)
{
    edge[i].to=to;
    edge[i].v=v;
    edge[i].next=last[from];
    last[from]=i;
}
int main()
{
    int f=read(),tx,ty,tz;
    For(i,1,f)
    {
        setup();
        n=read();
        m=read();
        w=read();
        m*=2;
        For(j,1,m)//這裏一開始又寫錯了,j全寫的i,還是沒吸取教訓。。
        {
            tx=read();
            ty=read();
            tz=read();
            add(tx,ty,tz,j++);
            add(ty,tx,tz,j);
        }
        For(j,1,w)
        {
            tx=read();
            ty=read();
            tz=read();
            que[j]=tx;
            add(tx,ty,tz*(-1),m+j);
        }
        For(j,1,w)
        {
            spfa(que[j]);
            if(t)
             break;
        }
        if(t)
         printf("YES\n");
        else
         printf("NO\n");
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章