POJ3259 回到过去(带负权的单源最短路径)

来源:互联网 发布:java刷题网站 编辑:程序博客网 时间:2024/05/01 09:32

有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;}