給定 N 個星球、M 條雙向道路、W 個單向蟲洞。道路花費時間為正,蟲洞花費時間為負(時間旅行)。判斷是否能從某個星球出發,經過一系列路徑回到起點,且總時間為負(即存在負環)。
將所有邊加入圖中:
對圖運行 Bellman-Ford,若第 N 輪鬆弛仍能更新距離,則存在負環。
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
struct Edge {
int u, v, w;
};
bool bellman_ford(int n, const vector<Edge>& edges) {
vector<int> dist(n + 1, 0); // 初始為 0 即可,因為只需檢測負環
// 執行 n 輪鬆弛
for (int i = 1; i <= n; i++) {
bool updated = false;
for (const auto& e : edges) {
if (dist[e.v] > dist[e.u] + e.w) {
dist[e.v] = dist[e.u] + e.w;
updated = true;
// 第 n 輪仍能更新,說明有負環
if (i == n) return true;
}
}
if (!updated) break; // 提前終止
}
return false;
}
int main() {
int F;
scanf("%d", &F);
while (F--) {
int N, M, W;
scanf("%d%d%d", &N, &M, &W);
vector<Edge> edges;
for (int i = 0; i < M; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edges.push_back({u, v, w});
edges.push_back({v, u, w}); // 雙向
}
for (int i = 0; i < W; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edges.push_back({u, v, -w}); // 蟲洞權值為負
}
if (bellman_ford(N, edges))
printf("YES\n");
else
printf("NO\n");
}
return 0;
}