zoukankan      html  css  js  c++  java
  • 虫洞

    链接

    https://www.acwing.com/problem/content/906/

    题目

    农夫约翰在巡视他的众多农场时,发现了很多令人惊叹的虫洞。

    虫洞非常奇特,它可以看作是一条 单向 路径,通过它可以使你回到过去的某个时刻(相对于你进入虫洞之前)。

    农夫约翰的每个农场中包含N片田地,M条路径(双向)以及W个虫洞。

    现在农夫约翰希望能够从农场中的某片田地出发,经过一些路径和虫洞回到过去,并在他的出发时刻之前赶到他的出发地。

    他希望能够看到出发之前的自己。

    请你判断一下约翰能否做到这一点。

    下面我们将给你提供约翰拥有的农场数量F,以及每个农场的完整信息。

    已知走过任何一条路径所花费的时间都不超过10000秒,任何虫洞将他带回的时间都不会超过10000秒。

    输入格式
    第一行包含整数F,表示约翰共有F个农场。

    对于每个农场,第一行包含三个整数N,M,W。

    接下来M行,每行包含三个整数S,E,T,表示田地S和E之间存在一条路径,经过这条路径所花的时间为T。

    再接下来W行,每行包含三个整数S,E,T,表示存在一条从田地S走到田地E的虫洞,走过这条虫洞,可以回到T秒之间。

    输出格式
    输出共F行,每行输出一个结果。

    如果约翰能够在出发时刻之前回到出发地,则输出“YES”,否则输出“NO”。

    数据范围
    1≤F≤5
    1≤N≤500,
    1≤M≤2500,
    1≤W≤200,
    1≤T≤10000,
    1≤S,E≤N
    输入样例:

    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
    

    思路

    虫洞可以理解为负权边,问题就是判断图中是否存在负环。那么就要用spfa算法。
    spfa求负环常用方法两种:
      1.(cnt[u])记录节点入队的次数,当某个节点入队次数n次,说明该节点在负环当中。
      2.(cnt[u])记录节点所在的最短路路径中的节点数,如果节点数大于n,说明该节点在负环中。
    一般来说用第二种的效率更高。
    众所周知,spfa随便都能被卡,然后还有各种优化:
      1.将spfa的队列改成栈
      2.如果spfa被卡,说明图中有大概率存在负环,需要加入一个变量表示经验值,记录所有节点的入队次数和(count),当(count>2n)时表示发现负环
      3.SLF优化,视情况可以用一下
      4.当求在整个图中是否存在负环,需要将所有点加入队列,所有点的距离可以初始化为0(不算优化
    以及:如果出题人能够写出在有负权图中比spfa跑的更快的算法,请随便ban!

    这道题中判断整个图中的负环,所以一开始需要将说有点加入队列中再跑spfa。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N=510,M=6000;
    int h[N],e[M],w[M],nex[M],idx,n;
    int d[N],q[N],st[N],cnt[N];
    bool spfa(){
        int hh=0,tt=0;
        for(int i=1;i<=n;++i){
            q[tt++]=i;
            st[i]=1;
            d[i]=0;
            cnt[i]=0;
        }
        while(hh!=tt){
            int u=q[--tt];//栈优化
            //int u=q[hh++];
            //if(hh==N) hh=0;
            st[u]=0;
            for(int i=h[u];~i;i=nex[i]){
                int v=e[i];
                if(d[v]>d[u]+w[i]){
                    d[v]=d[u]+w[i];
                    cnt[v]=cnt[u]+1;
                    if(cnt[v]>=n) return false;
                    if(!st[v]){
                        q[tt++]=v;
                        if(tt==N) tt=0;
                        st[v]=1;
                    }
                }
            }
        }
        return true;
    }
    void add(int u,int v,int t){
        e[idx]=v;
        w[idx]=t;
        nex[idx]=h[u];
        h[u]=idx++;
    }
    int main(){
        
        int m1,m2,T;
        scanf("%d",&T);
        while(T--){
            memset(h,-1,sizeof h);idx=0;
            scanf("%d%d%d",&n,&m1,&m2);
            while(m1--){
                int x,y,t;
                scanf("%d%d%d",&x,&y,&t);
                add(x,y,t);
                add(y,x,t);
            }
            while(m2--){
                int x,y,t;
                scanf("%d%d%d",&x,&y,&t);
                add(x,y,-t);
            }
            if(spfa()) puts("NO");
            else puts("YES");
        }
        return 0;
    }
    
  • 相关阅读:
    Object.defineProperty实现数据绑定
    trigger回调方法的实现
    window.print()打印页面指定内容(使用iframe保证原页面不失效)
    Visual Studio Code 快捷键大全(Windows)
    个人博客-逐梦博客,宋
    Vue.js项目在apache服务器部署后,刷新404的问题
    阿里云ECS服务器Ubuntu配置MySQL远程访问
    最全面的css布局
    js中数组常用方法总结
    PHP环境搭建
  • 原文地址:https://www.cnblogs.com/jjl0229/p/12760888.html
Copyright © 2011-2022 走看看