Bzoj1715虫洞

试题描述
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;
}

猜你喜欢

转载自www.cnblogs.com/WWHHTT/p/9664827.html