虫洞 Wormholes

https://loj.ac/problem/10085

题目描述

  给出一张图,有若干双向边(边权为正)和一些单向边(边权为负),求图上是否存在负环。

思路

  我们建图之后以每个点为出发点跑一遍dfs,在求最短路时判断节点是否在当前的访问序列中,如果在并且最短路小于0,那么图上必定存在一个环重复经过该节点并且边权为负,即存在负环,找到后可直接返回。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=550,M=5500;
int nxt[M],to[M],w[M],tot,head[N];
int vis[N],dis[N],f;
void clear()
{
    memset(head,-1,sizeof(head));
    memset(dis,0,sizeof(dis));
    memset(vis,0,sizeof(vis));
    tot=0;
}
void add_edge(int x,int y,int v)
{
    nxt[++tot]=head[x];
    head[x]=tot;
    to[tot]=y;
    w[tot]=v;
}
void spfa(int u,int st)
{
    if(f)return ;
    vis[u]=st;
    for(int i=head[u];~i;i=nxt[i])
    {
        int v=to[i];
        if(dis[v]>dis[u]+w[i])
        {
            dis[v]=dis[u]+w[i];
            if(!vis[v])spfa(v,st);
            if(vis[v]==st)
            {
                if(dis[v]<0)f=1;
                return;
            }
        }
    }
    vis[u]=0;
}
int main() 
{
    int cas;
    scanf("%d",&cas);
    while(cas--)
    {
        clear();
        int n,m,w;
        scanf("%d%d%d",&n,&m,&w);
        for(int i=1;i<=m;i++)
        {
            int s,e,t;
            scanf("%d%d%d",&s,&e,&t);
            add_edge(s,e,t);add_edge(e,s,t);
        }
        for(int i=1;i<=w;i++)
        {
            int s,e,t;
            scanf("%d%d%d",&s,&e,&t);
            add_edge(s,e,-t);
        }
        f=0;
        for(int i=1;i<=n;i++)
        {
            spfa(i,i);
            if(f)break ;
        }
        if(f)printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}

 

posted @ 2019-10-20 19:31  fbz  阅读(628)  评论(0编辑  收藏  举报