有N个农场,它们之间有M条普通的双向路径,同时有W条单向“虫洞”,通过普通路径需要花费时间,但通过虫洞却可以回到过去。问能否从任意一个点出发,通过某些普通路径或者“虫洞”再回到起始位置,使到达的时间早于出发的时间。
这是带负权的单源最短路径的入门题,按题目给定的边建好图,从任意一点起点开始,使用Bellman-Ford算法运行一遍,判断有没有回路就可以了。
#include <iostream> #include <cstdio> #include <climits> #include <algorithm> using namespace std; const int N = 505; const int E = 5205; const int MAX = 0xfffffff; struct Edge { int beg; int end; int dis; }; Edge edge[E]; int mindis[N]; int n, e; bool relax(int beg, int end, int dis) { if (mindis[beg] + dis < mindis[end]) { mindis[end] = mindis[beg] + dis; return true; } return false; } bool bellman_ford(int s) { bool flag; for (int i = 0; i < n; ++i) mindis[i] = MAX; mindis[s] = 0; for (int i = 0; i < n - 1; ++i) { flag = false; for (int j = 0; j < e; ++j) { if (relax(edge[j].beg, edge[j].end, edge[j].dis)) flag = true; } if (!flag) break; } for (int i = 0; i < e; ++i) { if (relax(edge[i].beg, edge[i].end, edge[i].dis)) return false; } return true; } void addedge(int u, int v, int dis) { edge[e].beg = u; edge[e].end = v; edge[e].dis = dis; ++e; } int main() { int T; int m, w; int u, v, dis; scanf("%d", &T); while (T--) { scanf("%d%d%d", &n, &m, &w); e = 0; for (int i = 0; i < m; ++i) { scanf("%d%d%d", &u, &v, &dis); --u; --v; addedge(u, v, dis); addedge(v, u, dis); } for (int i = 0; i < w; ++i) { scanf("%d%d%d", &u, &v, &dis); --u; --v; addedge(u, v, -dis); } if (bellman_ford(0)) printf("NO\n"); else printf("YES\n"); } return 0; }