补题报告08
题目背景
某天,奇异博士在纽约圣所研究维山帝之书时,发现了连接不同多元宇宙的传送门网络......
题目描述
经研究,奇异博士发现每个传送门都有固定的 “时间代价”—— 正数表示双向通行(往返时间代价相同均为正值),负数表示单向通行(从起点到终点的时间代价为负值)。
当存在一条从主宇宙出发,最终返回主宇宙的路径,且总时间代价减少时,就会引发时间悖论(旅行者可以通过循环该路径让时间无限倒流)。
请判断某次奇异博士规划的路线中是否存在这样的时间悖论路径。
注意:奇异博士当前所处的纽约圣所是编号为 1 的主宇宙,且各多元宇宙是互通的。
输入格式
第一行包含整数T,表示测试用例数量。
每个测试用例的第一行包含两个整数 n 和 m,分别表示多元宇宙的数量(编号 1~n)和传送门的数量。
接下来 m 行,每行包含三个整数a, b, c, 表示一个传送门:
- 若c ≥ 0:该传送门双向通行,从 a 到 b 和从 b 到 a 的时间代价均为 c
- 若c < 0:该传送门单向通行,仅能从 a 到 b,时间代价为 c
输出格式
对于每个测试用例,若存在引发时间悖论的路径,输出 “YES”,否则输出 “NO”。
输入输出样例
输入
2
3 3
1 2 1
2 3 2
3 1 -4
3 3
1 2 1
2 3 2
3 1 4
输出
YES
NO
说明/提示
对于全部的测试点,保证:
1 ≤ T ≤ 10
1 ≤ n ≤ 2×103,1 ≤ m ≤ 4×10^3
1 ≤ a,b ≤n,−10^4 ≤ c ≤1 0^4
解题思路
判断是否存在从主宇宙(节点1)出发并返回的路径,且总时间代价为负(时间减少),这样的路径会导致时间悖论。这个问题等价于在图中检测是否存在从节点1可达的负权环。可以使用SPFA算法来检测负权环。使用邻接表存储图结,节点1距离为0,其他节点距离为无穷大,使用队列进行松弛操作,如果某个节点被松弛的次数超过节点总数n,说明存在负权环。检测到负权环 → 输出"YES"(存在时间悖论),未检测到负权环 → 输出"NO"(不存在时间悖论)。
解决代码
#include <iostream>
#include <vector>
#include <queue>
#include <climits>
using namespace std;struct Edge {int to;int cost;
};bool hasNegativeCycle(int n, vector<vector<Edge>>& graph) {vector<int> dist(n+1, INT_MAX);vector<int> count(n+1, 0);vector<bool> inQueue(n+1, false);queue<int> q;dist[1] = 0;q.push(1);inQueue[1] = true;while (!q.empty()) {int u = q.front();q.pop();inQueue[u] = false;for (const Edge& e : graph[u]) {int v = e.to;int cost = e.cost;if (dist[u] != INT_MAX && dist[u] + cost < dist[v]) {dist[v] = dist[u] + cost;if (!inQueue[v]) {q.push(v);inQueue[v] = true;count[v]++;if (count[v] > n) {return true;}}}}}return false;
}int main() {int T;cin >> T;while (T--) {int n, m;cin >> n >> m;vector<vector<Edge>> graph(n+1);for (int i = 0; i < m; i++) {int a, b, c;cin >> a >> b >> c;if (c >= 0) {graph[a].push_back({b, c});graph[b].push_back({a, c});} else {graph[a].push_back({b, c});}}if (hasNegativeCycle(n, graph)) {cout << "YES" << endl;} else {cout << "NO" << endl;}}return 0;
}