虫洞 Wormholes
题目描述
给出一张图,有若干双向边(边权为正)和一些单向边(边权为负),求图上是否存在负环。
思路
我们建图之后以每个点为出发点跑一遍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; }