BZOJ 3373: [Usaco2004 Mar]Lying Livestock 说谎的牲畜

枚举每一头牛,反向这头牛说的边,并把边权置为 0 ,跑最短路,如果没有负环,那么 + + a n s

注意要从每个点都跑一边SPFA,枚举每个点 i ,然后 s p f a ( i ) ,与 a d d _ e d g e ( 0 , i ) ,然后 s p f a ( 0 ) 的效率是一样的。因为SPFA的复杂度是 O ( k m ) 的。

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

猜你喜欢

转载自blog.csdn.net/Milkyyyyy/article/details/81436772