码迷,mamicode.com
首页 > 其他好文 > 详细

[Usaco2006 Dec]Wormholes

时间:2019-06-04 20:55:29      阅读:132      评论:0      收藏:0      [点我收藏+]

标签:while   head   ring   set   register   getch   cst   class   har   

题目描述

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

标签:while   head   ring   set   register   getch   cst   class   har   

原文地址:https://www.cnblogs.com/akura/p/10976077.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!