[Usaco2006 Dec]Wormholes

Posted akura

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Usaco2006 Dec]Wormholes相关的知识,希望对你有一定的参考价值。

题目描述

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: 一个整数 F, 表示农场个数。

Line 1 of each farm: 三个整数 N, M, W。

Lines 2..M+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地,中间有一条用时T秒的小路。

Lines M+2..M+W+1 of each farm: 三个数(S, E, T)。表示在标号为S的地与标号为E的地,中间有一条可以使John到达T秒前的虫洞。

输出格式

Lines 1..F: 如果John能在这个农场实现他的目标,输出"YES",否则输出"NO"


由于题中所说,M条无向边已经连接了N个点,所以所有虫洞都必定属于至少一个简单环。

所以这题只需要判一下负环即可,这里我们可以用到SPFA。我们不停地将节点松弛,直到某个节点被松弛了超过n次,就说明有负环。

这种方法比较低效,这里介绍一种更高效的。记cnt[u]表示u到起点经过多少个点。那么每次松弛:if(dis[v]>dis[u]+edge(u,v)) then dis[v]=dis[u]+edge(u,v)时,我们令cnt[v]=cnt[u]+1。显然,起点到终点的最短路不会超过n-1个节点(起点不算)。那么我们松弛时一旦发现cnt[v]=n-1就说明有负环。

时间复杂度都是O(KM),但第二种明显更高效:第一种要将v入队n次才能判负环,而第二种只需要((n-1)/环的节点数)次即可。

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#define maxn 100001
#define maxm 100001
#define maxw 201
using namespace std;
 
struct edge
    int to,dis,next;
    edge()
    edge(const int &_to,const int &_dis,const int &_next) to=_to,dis=_dis,next=_next; 
e[maxm*2+maxw];
int head[maxn],k;
 
int dis[maxn],cnt[maxn];
bool inq[maxn];
int n,m,w;
 
inline int read()
    register int x(0),f(1); register char c(getchar());
    while(c<'0'||'9'<c) if(c=='-') f=-1; c=getchar(); 
    while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;

inline void add(const int &u,const int &v,const int &w) e[k]=edge(v,w,head[u]),head[u]=k++; 
 
inline bool spfa()
    memset(dis,0x3f,sizeof dis),memset(inq,false,sizeof inq),memset(cnt,0,sizeof cnt);
    queue<int> q; q.push(1),inq[1]=true,dis[1]=0;
    while(q.size())
        int u=q.front(); q.pop(),inq[u]=false;
        for(register int i=head[u];~i;i=e[i].next)
            int v=e[i].to;
            if(dis[v]>dis[u]+e[i].dis)
                dis[v]=dis[u]+e[i].dis,cnt[v]=cnt[u]+1;
                if(cnt[v]>=n) return true;
                if(!inq[v]) q.push(v),inq[v]=true;
            
        
    
    return false;

 
int main()
    int t=read();
    while(t--)
        memset(head,-1,sizeof head);
        n=read(),m=read(),w=read();
        for(register int i=1;i<=m;i++)
            int u=read(),v=read(),w=read();
            add(u,v,w),add(v,u,w);
        
        for(register int i=1;i<=w;i++)
            int u=read(),v=read(),w=read();
            add(u,v,-w);
        
        printf("%s\n",spfa()?"YES":"NO");
    
    return 0;

*数据与题目描述不符,建议数组开大点。

以上是关于[Usaco2006 Dec]Wormholes的主要内容,如果未能解决你的问题,请参考以下文章

[Usaco2006 Dec]Wormholes

bzoj 1715: [Usaco2006 Dec]Wormholes 虫洞spfa判负环

[USACO06DEC]虫洞Wormholes (负环模板)

洛谷 P2850 [USACO06DEC]虫洞Wormholes 题解

洛谷 P2850 [USACO06DEC]虫洞Wormholes 判负环

BZOJ 1717 Usaco 2006 Dec 产奶模式