题解【洛谷P3275】[SCOI2011]糖果

题面

其实是裸的差分约束吧 QwQ。

对于每一种情况分类讨论一下:

  • 如果 \(X=1\),则 \(A=B\),转换一下就变成了 \(A\geq B\)\(B\geq A\)
  • 如果 \(X=2\),则 \(A<B\),转换一下就变成了 \(B\geq A+1\)
  • 如果 \(X=3\),则 \(A\geq B\)
  • 如果 \(X=4\),则 \(A>B\),转换一下就变成了 \(A\geq B+1\)
  • 如果 \(X=5\),则 \(A\leq B\),转换一下就变成了 \(B\geq A\)

这里说一下差分约束最基本的建图方式:

  • 对于一个不等式 \(x_1 \geq x_2 + c\),我们都由 \(x_2\)\(x_1\) 连一条长度为 \(c\) 的边。

如何求最值呢?

结论:如果求的是最小值,那么我们就跑一遍最长路;否则就跑一遍最短路。

具体的方法就是对于每一个 \(x_i \geq c\) 的条件,建立一个超级源点 \(0\),由 \(0\)\(x_i\) 连一条长度为 \(c\) 的边。

因为本题中要求每个小朋友都要分到糖果,所以我们就建立一个超级源点 \(0\),向每一个点连一条长度是 \(1\) 的边。

最后跑一遍最长路就可以了。

注意如果图中有正环就说明无解。

而且这一题中用队列貌似会被卡,因此我们在找正环时把栈改成队列即可。

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 100003, M = 300003;

int n, m;
int cnt[N];
int tot, head[N], ver[M], nxt[M], edge[M];
bool st[N];
LL dist[N];
int stk[N];

inline void add(int u, int v, int w)
{
    ver[++tot] = v, edge[tot] = w, nxt[tot] = head[u], head[u] = tot;
}

inline bool SPFA()
{
    memset(cnt, 0, sizeof cnt);
    memset(st, false, sizeof st);
    memset(dist, 0xcf, sizeof dist);
    dist[0] = 0;
    int hh = 0, tt = 1;
    stk[0] = 0;
    while (hh != tt)
    {
        int u = stk[--tt];
        st[u] = false;
        for (int i = head[u]; i; i = nxt[i])
        {
            int v = ver[i], w = edge[i];
            if (dist[v] < dist[u] + w)
            {
                dist[v] = dist[u] + w;
                cnt[v] = cnt[u] + 1;
                if (cnt[v] >= n + 1) return true;
                if (!st[v])
                {
                    st[v] = true;
                    stk[tt++] = v;
                }
            }
        }
    }
    return false;
}

int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= m; i+=1)
    {
        int x, a, b;
        scanf("%d%d%d", &x, &a, &b);
        if (x == 1) add(b, a, 0), add(a, b, 0);
        else if (x == 2) add(a, b, 1);
        else if (x == 3) add(b, a, 0);
        else if (x == 4) add(b, a, 1);
        else add(a, b, 0);
    }
    for (int i = 1; i <= n; i+=1) add(0, i, 1);
    if (SPFA()) puts("-1");
    else 
    {
        LL ans = 0;
        for (int i = 1; i <= n; i+=1)
            ans += dist[i];
        printf("%lld\n", ans);
    }
    return 0;
}
posted @ 2020-03-04 14:22  csxsi  阅读(124)  评论(0编辑  收藏  举报