[SCOI2011] 糖果

差分约束系统:

正向建 (B-Age C)(A ightarrow B)(C),求最长路。

或反向建 (B-Age C)(B ightarrow B)(-C),求最短路。

均只能用 SPFA 做。注意判环!

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
 
int n, K, d[300005], enq[300005];
int head[300005], nex[300005], to[300005], w[300005];
bool inq[300005];
long long ans;
queue<int> q;
 
inline void add(const int& x, const int& y, const int& z) {
    nex[++head[0]]=head[x], head[x]=head[0], to[head[0]]=y, w[head[0]]=z;
}
 
inline bool spfa() {
    q.push(n+1), inq[n+1]=true, enq[n+1]=1;
    while (!q.empty()) {
        register int now=q.front(); q.pop(); inq[now]=false;
        for (register int i=head[now]; i; i=nex[i]) if (d[now]+w[i] > d[to[i]]) {
            d[to[i]]=d[now]+w[i];
            if (!inq[to[i]]) {q.push(to[i]), inq[to[i]]=true; if (++enq[to[i]]>=n) return true; }
        }
    }
    return false;
}
 
int main() {
    scanf("%d%d", &n, &K);
    while (K--) { 
        register int X, A, B;
        scanf("%d%d%d", &X, &A, &B);
        if (X==1) add(A, B, 0), add(B, A, 0); // A = B
        if (X==2) add(A, B, 1); // B > A
        if (X==3) add(B, A, 0); // A ≥ B
        if (X==4) add(B, A, 1); // A > B
        if (X==5) add(A, B, 0); // B ≥ A
        if (!(X&1) && (A==B)) {puts("-1
"); return 0; } // A ≠ A
    }
    for (int i=n; i; --i) add(n+1, i, 1);
    if (spfa()) {puts("-1
"); return 0; }
    for (int i=1; i<=n; ++i) ans+=d[i];
    printf("%lld
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/greyqz/p/11864527.html