题解 P2850虫洞Wormholes
P2850 [USACO06DEC]虫洞Wormholes
题意:只要能找到负环,就能回到过去,反之亦然。
spfa判断负环:如果任意一条边被修改大于n次,就代表这个图内一定存在至少一个负环。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define INF 0x3f3f3f3f
using namespace std;
#define N 1000010
int read()
{
int x=0,f=1;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return x*f;
}
struct edge{
int v,w,next;
}e[N<<1];
int head[N<<1],tot=0,cnt[N<<1];
bool vis[N];
int dis[N<<1],t,n,m,w;
void add(int u,int v,int w)
{
e[++tot].next=head[u];
e[tot].v=v;
e[tot].w=w;
head[u]=tot;
}
void clear()
{
memset(head,-1,sizeof(head));
memset(e,0,sizeof(e));
memset(cnt,0,sizeof(cnt));
tot=0;
memset(vis,0,sizeof(vis));
memset(dis,INF,sizeof(dis));
}
bool spfa(int s)
{
queue<int >q;
q.push(s);
dis[s]=0;
vis[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
if(!vis[v])
{
q.push(v);
vis[v]=1;
cnt[v]++;//判负环
}
if(cnt[v]>n) //松弛超过n次就说明有负环
return true;
}
}
}
return false;
}
int main()
{
freopen("input.txt","r",stdin);
t=read();
while(t--)
{
clear();
n=read(),m=read(),w=read();
rep(i,1,m)
{
int x,y,z;
x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
rep(i,1,w)
{
int x,y,z;
x=read(),y=read(),z=read();
add(x,y,-z);//此处不能建双向边
}
if(spfa(1))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}