1. 程式人生 > >Bzoj1715蟲洞

Bzoj1715蟲洞

git sfpa bsp style 但是 tab 清晰 table 連接

試題描述
John 在他的農場中閑逛時發現了許多蟲洞。蟲洞可以看作一條十分奇特的有向邊,並可以使你返回到過去的一個時刻(相對你進入蟲洞之前)。John 的每個農場有 M 條小路(無向邊)連接著 N(從 1 到 N 標號)塊地,並有 W 個蟲洞。
現在 John 想借助這些蟲洞來回到過去(在出發時刻之前回到出發點),請你告訴他能辦到嗎。 John 將向你提供 F 個農場的地圖。沒有小路會耗費你超過 10^4秒的時間,當然也沒有蟲洞回幫你回到超過 10^4秒以前。
輸入
第一行一個整數 F,表示農場個數;

對於每個農場:

第一行,三個整數 N,M,W;
接下來 M 行,每行三個數 S,E,T,表示在標號為 S 的地與標號為 E 的地中間有一條用時 T 秒的小路;
接下來 W 行,每行三個數 S,E,T,表示在標號為 S 的地與標號為 E 的地中間有一條可以使 John 到達 T 秒前的蟲洞。
輸出
輸出共 F 行,如果 John 能在第 i 個農場實現他的目標,就在第 i 行輸出 YES,否則輸出 NO。
輸入示例
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
輸出示例
NO
YES
其他說明
對於全部數據,1≤F≤5,1≤N≤500,1≤M≤2500,1≤W≤200,1≤S,E≤N,∣T∣≤104。

題目描述還是很清晰的,大概就是給一個圖,判斷圖中是否存在負環,簡單的一個SPFA就可以跑

然而要註意的是,這道題用普通的BFS會被卡(不知道SLF能不能過,有興趣的同學可以試一下)

判斷負環的方法很簡單,如果我們發現一個點已經被更新過了,但是dis值卻比當前點還要小,就證明它從這個點出發後,跑了一個小於零的路徑又回到了原點,證明有負環

下面給出代碼

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#define cl(a) memset(a,0,sizeof(a))
using namespace std;
inline int rd(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch==-) f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-0;
    return x*f;
}
inline void write(int x){
    if(x<0) putchar(-),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+0);
    return ;
}
int T;
int n,m,w;
int total=0;
int head[10006],nxt[10006],to[10006],v[10006];
int dis[1006];
void add(int x,int y,int z){
    total++;
    to[total]=y;
    v[total]=z;
    nxt[total]=head[x];
    head[x]=total;
    return ;
}
int book[1006];
int f=0;
void SPFA(int x){//DFS版的SFPA 
    for(int e=head[x];e;e=nxt[e]){
        if(dis[to[e]]>dis[x]+v[e]){
            dis[to[e]]=dis[x]+v[e];
            if(book[to[e]]){//如果一個點已經跑過了,但是值比原來還要小,就是負環 
                f=1;
                return ;
            }
            book[to[e]]=1;
            SPFA(to[e]);
            book[to[e]]=0;
        }
    }
    return ;
}
int main(){
    T=rd();
    while(T--){
        f=0;
        total=0;
        cl(head),cl(nxt),cl(to),cl(v),cl(book);
        memset(dis,127,sizeof(dis));
        n=rd(),m=rd(),w=rd();
        for(int i=1;i<=m;i++){
            int x,y,z;
            x=rd(),y=rd(),z=rd();
            add(x,y,z);
            add(y,x,z);
        }
        for(int i=1;i<=w;i++){
            int x,y,z;
            x=rd(),y=rd(),z=rd();
            add(x,y,0-z);//蟲洞因為是往回倒時間,所以存成負數 
        }
        dis[1]=0;
        SPFA(1);
        if(f) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

Bzoj1715蟲洞