其实是裸的差分约束吧 QwQ。
对于每一种情况分类讨论一下:
- 如果 (X=1),则 (A=B),转换一下就变成了 (Ageq B) 且 (Bgeq A);
- 如果 (X=2),则 (A<B),转换一下就变成了 (Bgeq A+1);
- 如果 (X=3),则 (Ageq B);
- 如果 (X=4),则 (A>B),转换一下就变成了 (Ageq B+1);
- 如果 (X=5),则 (Aleq B),转换一下就变成了 (Bgeq 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
", ans);
}
return 0;
}