1 介绍
本专题用来记录差分约束的题目。
差分约束类的题目,一般有如下两类问题:
- 求不等式组的可行解。
- 求最大值或者最小值,这里的最值指的是每个变量的最值。
对于第一类问题,需要满足如下条件:从原点出发,一定可以经过所有的边。
第一类问题的求解步骤如下:
- 先将每个不等式
xi <= xj + ck
,转化成一条从xj
走到xi
,长度为ck
的一条边。 - 寻找一个超级原点,使得该原点一定可以遍历到所有的边。
- 从原点求一遍单源最短路。结果1:如果存在负环,则原不等式组一定无解。结果2:如果没有负环,则
dist[i]
就是原不等式组的一个可行解。
对于第二类问题,如果求的是最小值,则应该求最长路;如果求的是最大值,则应该求最短路。
如何转化xi <= c
,其中c
是一个常数?方法:建立一个超级原点0,然后构建0 --> i
的边,其长度为c
。
以求xi
的最大值为例:求所有从xi
出发,构成的不等式链xi <= xj + c1 <= xk + c2 + c1 <= ... <= c1 + c2 + ...
。可以计算出一个xi
的上界。最终xi
的最大值等于所有上界的最小值。
2 训练
题目1:1169糖果
C++代码如下,
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010, M = 300010;
int n, m;
int h[N], e[M], w[M], ne[M], idx;
LL dist[N];
int q[N], cnt[N];
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() {
int hh = 0, tt = 1;
memset(dist, -0x3f, sizeof dist);
dist[0] = 0;
q[0] = 0;
st[0] = true;
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]) {
dist[j] = dist[t] + w[i];
cnt[j] = cnt[t] + 1;
if (cnt[j] >= n + 1) return false;
if (!st[j]) {
q[tt++] = j;
st[j] = true;
}
}
}
}
return true;
}
int main() {
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
while (m--) {
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