农夫约翰在巡视他的众多农场时,发现了很多令人惊叹的虫洞。
虫洞非常奇特,它可以看作是一条?单向?路径,通过它可以使你回到过去的某个时刻(相对于你进入虫洞之前)。
农夫约翰的每个农场中包含?N?片田地,M?条路径(双向)以及?W?个虫洞。
现在农夫约翰希望能够从农场中的某片田地出发,经过一些路径和虫洞回到过去,并在他的出发时刻之前赶到他的出发地。
他希望能够看到出发之前的自己。
请你判断一下约翰能否做到这一点。
下面我们将给你提供约翰拥有的农场数量?F,以及每个农场的完整信息。
已知走过任何一条路径所花费的时间都不超过 10000?秒,任何虫洞将他带回的时间都不会超过?10000 秒。
第一行包含整数?F,表示约翰共有?F?个农场。
对于每个农场,第一行包含三个整数?N,M,W。
接下来?M?行,每行包含三个整数?S,E,T,表示田地?S 和?E?之间存在一条路径,经过这条路径所花的时间为?T。
再接下来?W?行,每行包含三个整数?S,E,T,表示存在一条从田地?S?走到田地?E?的虫洞,走过这条虫洞,可以回到?T?秒之前。
输出共?F?行,每行输出一个结果。
如果约翰能够在出发时刻之前回到出发地,则输出?YES
,否则输出?NO
。
1≤F≤5
1≤N≤500
1≤M≤2500
1≤W≤200
1≤T≤10000
1≤S,E≤N
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
NO
YES
通过 SPFA(Shortest Path Faster Algorithm)算法检测图中是否存在负权环。
算法思想如下:
1. 使用 SPFA 算法求解单源最短路径问题,计算从每个点出发到其他所有点的最短路径。
2. 在遍历边的过程中,如果某个点被松弛了 `n` 次(`n` 为节点数),说明存在负权环。
3. 如果存在负权环,则输出 "YES",否则输出 "NO"。
具体实现中,将图中的正权边按照正常的方式添加,而将负权边的权值取相反数,这样就可以转化为求解负权环的问题。如果存在负权环,说明图中存在一条路径,经过这个路径的权值和为负,即存在一组边,形成了一个负权环。
?
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<utility>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<math.h>
#include<map>
#include<sstream>
#include<deque>
#include<unordered_map>
using namespace std;
typedef long long LL;
const int N = 505, M = 5205;
int n, m1, m2;
int h[N], e[M], w[M], ne[M], idx;
int q[N], vis[N], cnt[N],d[N];
void add(int a, int b, int c) {
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int spfa() {
memset(d, 0x3f, sizeof d);
memset(cnt, 0, sizeof cnt);
memset(vis, 0, sizeof vis);
int hh = 0, tt = 0;
for (int i = 1; i <= n; i++) {
q[tt++] = i;
vis[i] = 1;
}
while (hh != tt) {
int t = q[hh++];
if (hh == N)hh = 0;
vis[t] = 0;
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i];
if (d[j] > d[t] + w[i]) {
d[j] = d[t] + w[i];
cnt[j] = cnt[t] + 1;
if (cnt[j] > n)return 1;
if (!vis[j]) {
q[tt++] = j;
if (tt == N)tt = 0;
vis[j] = 1;
}
}
}
}
return 0;
}
int main() {
int T;
cin >> T;
while (T--) {
memset(h, -1, sizeof h);
idx = 0;
scanf("%d%d%d", &n, &m1, &m2);
int a, b, c;
while (m1--) {
scanf("%d%d%d", &a, &b, &c);
add(a, b, c), add(b, a, c);
}
while (m2--) {
scanf("%d%d%d", &a, &b, &c);
add(a, b, -c);
}
if (spfa())cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}