枚举每一头牛,反向这头牛说的边,并把边权置为 ,跑最短路,如果没有负环,那么 。
注意要从每个点都跑一边SPFA,枚举每个点 ,然后 ,与 ,然后 的效率是一样的。因为SPFA的复杂度是 的。
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
const int N = 105, M = 1005;
struct Edge {
int u, v, c;
} e[M];
std::vector<Edge> edges;
std::vector<int> G[N];
std::queue<int> Q;
int p[N][M], n, dis[N], inq[N], cnt[N];
int read() {
int x = 0; char c = getchar();
while (c < '0' || c > '9') c = getchar();
while (c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return x;
}
void swap(int &x, int &y) {
x ^= y, y ^= x, x ^= y;
}
void add_edge(int u, int v, int c) {
G[u].push_back(edges.size());
edges.push_back((Edge){u, v, c});
}
bool spfa() {
memset(inq, 0, sizeof inq);
memset(cnt, 0, sizeof cnt);
memset(dis, 0x3f, sizeof dis);
while (!Q.empty()) Q.pop();
Q.push(0); inq[0] = cnt[0] = 1; dis[0] = 0;
while (!Q.empty()) {
int u = Q.front(); Q.pop(); inq[u] = 0;
int sz = G[u].size();
for (int i = 0; i < sz; ++i) {
Edge e = edges[G[u][i]];
if (dis[u] + e.c < dis[e.v]) {
dis[e.v] = dis[u] + e.c;
if (!inq[e.v]) {
if (++cnt[e.v] > n) return false;
Q.push(e.v); inq[e.v] = 1;
}
}
}
}
return true;
}
int main() {
n = read(); int m = read(), ans = 0;
for (int i = 1; i <= m; ++i) {
int a = read(), b = read(), c = read();
e[i] = (Edge){b, c, -1}; p[a][++p[a][0]] = i;
}
for (int i = 1; i <= n; ++i) {
edges.clear();
for (int j = 1; j <= n; ++j) G[j].clear();
for (int j = 1; j <= p[i][0]; ++j) {
swap(e[p[i][j]].u, e[p[i][j]].v);
e[p[i][j]].c = 0;
}
for (int j = 1; j <= m; ++j)
add_edge(e[j].u, e[j].v, e[j].c);
for (int i = 1; i <= n; ++i) add_edge(0, i, 0);
if (spfa()) ++ans;
for (int j = 1; j <= p[i][0]; ++j) {
swap(e[p[i][j]].u, e[p[i][j]].v);
e[p[i][j]].c = -1;
}
}
printf("%d\n", ans);
return 0;
}