判断负圈的版子题
之前的题用Bellman法判断过了。
这里就用spfa判断一下负圈吧。
用spfa判断负圈的方法有两种:
1.记录节点入队的次数,若次数>n-1则有负圈
2.记录起点到节点经历的边数,若边数>n-1则有负圈(也可以理解为途经的节点数)
第二种会更快一点
代码如下:
#include<iostream> #include<algorithm> #include<queue> #include<cstdio> using namespace std; const int max_n = 700; const int max_m = 3000; const int inf = 2e9; struct edge{ int to, cost, next; }E[max_m << 1]; int head[max_n]; int cnt = 1; void add(int from, int to, int cost) { E[cnt].to = to;E[cnt].cost = cost; E[cnt].next = head[from];head[from] = cnt++; } int d[max_n]; int cct[max_n]; bool vis[max_n]; bool spfa(int s,int n) { fill(d, d + max_n, inf); fill(cct, cct + max_n, 0); fill(vis, vis + max_n, false); queue<int> que;que.push(s); d[s] = 0;vis[s] = true; while (!que.empty()) { int u = que.front(); que.pop();vis[u] = false; for (int i = head[u];i;i = E[i].next) { edge& e = E[i]; if (d[e.to] > d[u] + e.cost) { d[e.to] = d[u] + e.cost; cct[e.to] = cct[u] + 1; if (cct[e.to] >= n)return true; if (vis[e.to])continue; vis[e.to] = true; que.push(e.to); } } }return false; } int N, M, W; int main() { int tcase;scanf("%d", &tcase); while (tcase--) { fill(head, head + max_n, 0);cnt = 1; scanf("%d %d %d", &N, &M, &W); for (int i = 1, u, v, c;i <= M;++i) { scanf("%d %d %d", &u, &v, &c); add(u, v, c);add(v, u, c); }for (int i = 1, u, v, c;i <= W;++i) { scanf("%d %d %d", &u, &v, &c); add(u, v, -c); }spfa(1, N) ? printf("YES\n") : printf("NO\n"); } }