题意:field块地,path条路,hole个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。每条路给出起点、终点和经过时间,我们的任务是判断能否从某地出发,在过去的某个时间回到该地。
思路:即判断是否有负权回路,有的话就能回到原地。
关于SPFA:SPFA 在形式上和广度(宽度)优先搜索非常类似,不同的是bfs中一个点出了队列就不可能重新进入队列,
但是SPFA中一个点可能在出队列之后再次被放入队列,也就是一个点改进过其它的点之后,过了一段时间可能本身被改进(重新入队),于是再次用来改进其它的点,这样反复迭代下去。 由dijkstra可知,源点先入队,之后n-1个点逐次入队
如果一个点被改进的次数大于n-1,说明存在负环。(参考LRJ紫书)
//cnt忘记初始化导致Runtime error
/*
SPFA 在形式上和广度(宽度)优先搜索非常类似,不同的是bfs中一个点出了队列就不可能重新进入队列,
但是SPFA中一个点可能在出队列之后再次被放入队列,也就是一个点改进过其它的点之后,过了一段时间可能本身被改进(重新入队),
于是再次用来改进其它的点,这样反复迭代下去。
由dijkstra可知,源点先入队,之后n-1个点逐次入队
如果一个点被改进的次数大于n-1,说明存在负环
参考LRJ紫书
*/
#include<stdio.h>
#include<queue>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
const int MAXE = 5500;
const int MAXN = 550;
int vis[MAXN],num[MAXN],dist[MAXN],head[MAXN];
int cnt;//记录边数
int n,m,w;
struct Edge
{
int v,w,next;
}edge[MAXE];
void AddEdge(int u, int v, int w)
{
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
bool spfa()
{
memset(vis, 0, sizeof(vis));
memset(num, 0, sizeof(num));
for(int i = 1; i <= n; ++i)
dist[i] = inf;
queue<int>q;
q.push(1);
dist[1] = 0;
vis[1] = 1;
num[1]++;
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = 0;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].v;
if(dist[v] > dist[u] + edge[i].w)
{
dist[v] = dist[u] + edge[i].w;
if(!vis[v])
{
q.push(v);
vis[v] = 1;
num[v]++;
if(num[v] > n-1) //结点v被松弛的次数超过n-1次
return true;
}
}
}
}
return false;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset(head,-1,sizeof(head));
cnt=0;
scanf("%d%d%d",&n,&m,&w);
for(int i = 1; i <= m; ++i)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
AddEdge(a, b, c);
AddEdge(b, a, c);
}
for(int i = 1; i <= w; ++i)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
AddEdge(a, b, -c);
}
if(spfa()) printf("YES\n");
else printf("NO\n");
}
return 0;
}