P2850 [USACO06DEC]Wormholes G - SPFA求负环

新博客地址:https://gyrojeff.top,欢迎访问! 本文为博客自动同步文章,为了更好的阅读体验,建议您移步至我的博客👇

本文标题:P2850 [USACO06DEC]Wormholes G - SPFA求负环

文章作者:gyro永不抽风

发布时间:2020年09月20日 - 13:09

最后更新:2020年09月20日 - 13:09

原始链接:http://hexo.gyrojeff.moe/2020/09/20/P2850-USACO06DEC-Wormholes-G-SPFA%E6%B1%82%E8%B4%9F%E7%8E%AF/

许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 转载请保留原文链接及作者!

题目

题目背景

题目描述

John 在他的农场中闲逛时发现了许多虫洞。虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前)。

John 的每个农场有 mm 条小路(无向边)连接着 nn 块地(从 1n1 \sim n 标号),并有 ww 个虫洞。

现在 John 想借助这些虫洞来回到过去(出发时刻之前),请你告诉他能办到吗。

输入格式

输入的第一行是一个整数 TT,代表测试数据的组数。

每组测试数据的格式如下:

每组数据的第一行是三个用空格隔开的整数,分别代表农田的个数 nn,小路的条数 mm,以及虫洞的个数 ww

每组数据的第 22 到第 (m+1)(m + 1) 行,每行有三个用空格隔开的整数 u,v,pu, v, p,代表有一条连接 uuvv 的小路,经过这条路需要花费 pp 的时间。

每组数据的第 (m+2)(m + 2) 到第 (m+w+1)(m + w + 1) 行,每行三个用空格隔开的整数 u,v,pu, v, p,代表点 uu 存在一个虫洞,经过这个虫洞会到达点 vv,并回到 pp 秒之前。

输出格式

对于每组测试数据,输出一行一个字符串,如果能回到出发时刻之前,则输出 YES,否则输出 NO

输入输出样例

输入 #1
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
输出 #1
NO
YES

说明/提示

样例 2 解释

John 只需要沿着 12311 \rightarrow 2 \rightarrow 3 \rightarrow 1 的路径一直转圈即可,每转完一圈,时间就会减少一秒。

数据范围与约定

对于 100%100\% 的数据,1T51 \le T \le 51n5001 \le n \le 5001m25001 \le m \le 25001w2001 \le w \le 2001p1041 \le p \le 10^4

题解

这里其实很显然,就是要求有没有负环。这里我主要想说的是为什么在这道题当中,从任意一点出发跑SPFA都是可以判断的。首先,在没有虫洞的情况下,图是双向且连同的,那就意味着无论如何我们都可以在节点之间往返。所以,如果在某一点存在一个负环,那必定可以从其他任意一点到达,从而不断优化最短路,达到用SPFA判断负环的目的。

代码

下面是代码,其实就是裸的SPFA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>
#include <queue>
#include <cstring>
#define int long long

using namespace std;

const int maxm = 25005;
const int maxn = 5005;
const int maxw = 2005;

int n, m, T, w, ecnt = 2, head[maxn], dis[maxn], cnt[maxn];
bool in[maxn];
struct edge { int to, next, w; } g[(maxm << 1) + maxw];
void add_edge(int u, int v, int w) { g[ecnt] = (edge) { v, head[u], w }; head[u] = ecnt ++; }
struct node { int dis, pos; };

bool spfa() {
for (int i = 1; i <= n; i ++) dis[i] = 2e9, in[i] = false;
queue<node> q;
dis[1] = 0; q.push((node) { dis[1], 1 });
in[1] = true;
cnt[1] = 0;
while (!q.empty()) {
int u = q.front().pos; q.pop(); in[u] = false;
for (int e = head[u]; e; e = g[e].next) {
int v = g[e].to;
if (dis[v] > dis[u] + g[e].w) {
dis[v] = dis[u] + g[e].w;
cnt[v] = cnt[u] + 1;
if (cnt[v] >= n) return true;
if (!in[v]) {
q.push((node) { dis[v], v });
in[v] = true;
}
}
}
}
return false;
}

signed main() {
cin >> T;
while (T --> 0) {
cin >> n >> m >> w;
ecnt = 2;
memset(head, 0, sizeof(head));
memset(g, 0, sizeof(g));
for (int i = 1; i <= m; i ++) {
int u, v, p; cin >> u >> v >> p;
add_edge(u, v, p);
add_edge(v, u, p);
}
for (int i = 1; i <= w; i ++) {
int u, v, p; cin >> u >> v >> p;
add_edge(u, v, -p);
}
bool ans = spfa();
cout << (ans ? "YES" : "NO") << endl;
}
return 0;
}
posted @ 2020-11-10 17:54  gyro永不抽风  阅读(153)  评论(0编辑  收藏  举报