P2850 [USACO06DEC]Wormholes G(负环判定)
作者:互联网
题目描述
John 在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。
John 的每个农场有 mmm 条小路(无向边)连接着 nnn 块地(从 1∼n1 \sim n1∼n 标号),并有 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
。
输入输出样例
输入 #12 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; }
标签:cnt,USACO06DEC,int,memset,head,tot,负环,P2850,sizeof 来源: https://www.cnblogs.com/lipoicyclic/p/12748100.html