负环 差分约束 T3 P3275 [SCOI2011]糖果 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
题目描述
幼儿园里有 个小朋友, 老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果。但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配糖果的时候, 需要满足小朋友们的 个要求。幼儿园的糖果总是有限的, 想知道他至少需要准备多少个糖果,才能使得每个小朋友都能够分到糖果,并且满足小朋友们所有的要求。
输入格式
输入的第一行是两个整数 ,。接下来 行,表示这些点需要满足的关系,每行 个数字,,,。
- 如果 , 表示第 个小朋友分到的糖果必须和第 个小朋友分到的糖果一样多;
- 如果 , 表示第 个小朋友分到的糖果必须少于第 个小朋友分到的糖果;
- 如果 , 表示第 个小朋友分到的糖果必须不少于第 个小朋友分到的糖果;
- 如果 , 表示第 个小朋友分到的糖果必须多于第 个小朋友分到的糖果;
- 如果 , 表示第 个小朋友分到的糖果必须不多于第 个小朋友分到的糖果;
输出格式
输出一行,表示 老师至少需要准备的糖果数,如果不能满足小朋友们的所有要求,就输出 。
样例 #1
样例输入 #1
5 7
1 1 2
2 3 2
4 4 1
3 4 5
5 4 5
2 3 5
4 5 1
样例输出 #1
11
提示
对于 的数据,保证
对于 的数据,保证
对于所有的数据,保证
思路
差分约束 (1)求不等式组的可行解 源点需要满足条件:从源点出发, 一定可以走到所有边 步骤: 1. 先将每个不等式 , 转化为一条从 走到 , 长度为 的边 2. 找一个超级源点(从 中得出), 使得该源点一定可以遍历到所有边 3. 从源点求一遍单源最短路 1. 如果有负环, 则无解 2. 如果没有负环, 则就是原不等式组的一个可行解 (2)如何求最大值或者最小值, 这里的最值指的是每个变量的最值 结论:如果求得是最小值, 则应该求最长路; 如果求的是最大值, 应该求最短路。 求 最大值:求所有从 出发, 构成的不等式链: 得到一个上界, 最终 的最大值就是所有上界的最小值 求 最小值:求所有从 出发, 构成的不等式链: 得到一个下界, 最终 的最小值就是所有下界的最大值
那么该题需要把不等式统一为 :
- x = 1时, 对应的转换式为 ,
- x = 2时, 对应的转换式为
- x = 3时, 对应的转换式为
- x = 4时, 对应的转换式为
- x = 5时, 对应的转换式为
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
using namespace std;
const int N = 1e5 + 10, M = 1e6 + 10;
typedef long long LL;
int h[N], e[M], w[M], ne[M], idx;
int q[N], cnt[N];
LL dist[N];
int n, m;
bool st[N];
void add(int a, int b, int c) { e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++; }
bool spfa()
{
memset(dist, -0x3f, sizeof dist);
int hh = 0, tt = 1;
q[0] = 0;
dist[0] = 0;
st[0] = true;
int count = 1;
while (hh != tt)
{
int t = q[--tt];
st[t] = false;
for (int i = h[t]; ~i; i = ne[i])
{
int j = e[i];
if (dist[j] < dist[t] + w[i])
{
count++;
dist[j] = dist[t] + w[i];
cnt[j] = cnt[t] + 1;
if (cnt[j] > n + 1 || count > 5000 * n)
return false;
if (!st[j])
{
st[j] = true;
q[tt++] = j;
}
}
}
}
return true;
}
int main()
{
memset(h, -1, sizeof h);
cin >> n >> m;
while (m--)
{
int x, a, b;
cin >> x >> a >> b;
if (x == 1)
add(a, b, 0), add(b, a, 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 if (x == 5)
add(a, b, 0);
}
for (int i = 1; i <= n; i++)
add(0, i, 1);
if (!spfa())
cout << -1 << endl;
else
{
LL res = 0;
for (int i = 1; i <= n; i++)
res += dist[i];
cout << res << endl;
}
return 0;
}