P2850 [USACO06DEC]Wormholes G(负环判定)

题目描述

John 在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。

John 的每个农场有 mmm 条小路(无向边)连接着 nnn 块地(从 1∼n1 sim n1n 标号),并有 www 个虫洞。

现在 John 想借助这些虫洞来回到过去(出发时刻之前),请你告诉他能办到吗。

输入格式

输入的第一行是一个整数 TTT,代表测试数据的组数。

每组测试数据的格式如下:

每组数据的第一行是三个用空格隔开的整数,分别代表农田的个数 nnn,小路的条数 mmm,以及虫洞的个数 www。

每组数据的第 222 到第 (m+1)(m + 1)(m+1) 行,每行有三个用空格隔开的整数 u,v,pu, v, pu,v,p,代表有一条连接 uuu 与 vvv 的小路,经过这条路需要花费 ppp 的时间。

每组数据的第 (m+2)(m + 2)(m+2) 到第 (m+w+1)(m + w + 1)(m+w+1) 行,每行三个用空格隔开的整数 u,v,pu, v, pu,v,p,代表点 uuu 存在一个虫洞,经过这个虫洞会到达点 vvv,并回到 ppp 秒之前。

输出格式

对于每组测试数据,输出一行一个字符串,如果能回到出发时刻之前,则输出 YES,否则输出 NO

输入输出样例

输入 #1
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
输出 #1
NO
YES

显然,只要存在负环就一定能回到过去,不存在的话是不可能的。
注意,这个题是给出一个图后往上添加负权边,不存在两个点之间只有一条负边的情况。
然后这个题没有起点终点,但其实无所谓。
注意开数组大小时,M必须要大于2500*2*500!!WA了半天TAT
#include <bits/stdc++.h>
#define N 505
#define M 3005
using namespace std;
int n,m,w,tot=0;
int head[N],edge[2*M],ver[2*M],Next[2*M],cnt[N],d[N];
bool v[N];
void add(int x,int y,int z)
{
    ver[++tot]=y,edge[tot]=z,Next[tot]=head[x],head[x]=tot;
}
bool spfa()
{
    queue<int>q;
    d[1]=0,v[1]=1,cnt[1]=0;
    q.push(1);
    while(q.size())
    {
        int x=q.front();
        q.pop();
        v[x]=0;
        int i;
        for(i=head[x];i;i=Next[i])
        {
            int y=ver[i],z=edge[i];
            if(d[y]>d[x]+z)
            {
                d[y]=d[x]+z;
                cnt[y]++;
                if(cnt[y]>=n)return 1;
                if(!v[y])q.push(y),v[y]=1;
            }
        }
    }
    while(q.size())q.pop();
    return 0;
}
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        memset(head,0,sizeof(head));
        memset(edge,0,sizeof(edge));
        memset(ver,0,sizeof(ver));
        memset(Next,0,sizeof(Next));
        memset(cnt,0,sizeof(cnt));
        memset(v,0,sizeof(v));
        memset(d,0x3f,sizeof(d));
        tot=0;
        cin>>n>>m>>w;
        int i,u,v,time;
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&u,&v,&time);
            add(u,v,time);
            add(v,u,time);
        }
        for(i=1;i<=w;i++)
        {
            scanf("%d%d%d",&u,&v,&time);
            add(u,v,-time);//手动转换为负数 
        }
        if(spfa())cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}


原文地址:https://www.cnblogs.com/lipoicyclic/p/12748100.html