若是一个系统由 n 个变量和 m 个约束条件组成,每一个约束条件形如 \(x_j-x_i<=b_k\),其中 \(i,j\in[1,n],k\in[1,m]\),则称其为差分约束系统(System of Difference Constraints)。亦即,差分约束系统是求解关于特殊的 \(N\) 元一次不等式组的方法。html
咱们先来看一个简单的数学问题,以下给定 4 个变量和 5 个不等式约束条件,求 \(x_3-x_0\) 的最大值。node
咱们能够经过不等式的两两加获得三个结果,学习
由以上结果很容易得知,\(x_3-x_0\) 的最大值是 7,也就是上面三式里的最小值。spa
这个例子很简单,只有 4 个变量和 5 个不等式约束条件,那若是有上百变量上千约束条件呢?仅凭肉眼手工计算效率太差,所以咱们须要一个较为系统的解决办法。code
咱们先来看一幅图,以下,给定四个小岛以及小岛之间的有向距离,问从 0 号岛到 3 号岛的最短距离。箭头指向的线表明两个小岛之间的有向边,蓝色数字表明距离权值。htm
这个问题就是经典的最短路问题。因为这个图比较简单,咱们能够枚举全部的路线,发现总共三条路线,以下:blog
0 -> 3,长度为 8ip
0 -> 2 -> 3,长度为 7 + 2 = 9ci
0 -> 1 -> 2 -> 3,长度为 2 + 3 + 2 = 7get
最短路为三条线路中的长度的最小值,即 7,因此最短路的长度就是 7。细心的读者会发现,这幅图和最上方的五个不等式约束条件是有所关联的,但这个关联并非巧合,而正是咱们接下来要讲的那个 "系统的解决办法"。
差分约束系统中的每一个约束条件 \(x_i-x_j<=c_k\) 均可以变造成 \(x_i<=x_j+c_k\),这与单源最短路中的三角形不等式 \(dist[y]<=dist[x]+z\) 很是类似。
所以,咱们能够把每一个变量 \(x_i\) 看作图中的一个结点,对于每一个约束条件 \(x_i-x_j<=c_k\),当作是从结点 \(j\) 向结点 \(i\) 的一条权值为 \(c_k\) 的有向边,因而咱们就能够把一个差分约束系统转化成图的最短路问题。
然而在实际问题中状况每每会复杂得多,例如,把条件约束里的全部等号去掉,
这个时候咱们就须要将上面的小于号转换成小于等于号。
当 \(x_i\) 被限定只能是整数时,这个转换就会很是简单,
差分约束问题下,
CodeVS 4416 - FFF 团卧底的后宫
给出 n
个形如 $x_i - x_j <= d $ 或 $x_i - x_j >= d $ 的不等式,求一组使 与 差最大的解,输出最大差值,若无解输出 -1
,若 与 的差为无限大则输出 -2
。
#include <cstdio> #include <climits> #include <algorithm> #include <queue> const int MAXN = 1000; const int MAXM = 10000; struct Edge; struct Node; struct Node { Edge *edges; bool inQueue; int dist; int count; } nodes[MAXN]; struct Edge { Node *from, *to; int w; Edge *next; Edge(Node *from, Node *to, int w) : from(from), to(to), w(w), next(from->edges) {} }; int n, m, k; inline void addEdge(int from, int to, int w) { nodes[from].edges = new Edge(&nodes[from], &nodes[to], w); } inline bool bellmanFord() { std::queue<Node *> q; q.push(&nodes[0]); while (!q.empty()) { Node *node = q.front(); q.pop(); node->inQueue = false; for (Edge *edge = node->edges; edge; edge = edge->next) { if (edge->to->dist > node->dist + edge->w) { edge->to->dist = node->dist + edge->w; if (!edge->to->inQueue) { edge->to->inQueue = true; edge->to->count++; q.push(edge->to); if (edge->to->count > n) { return false; } } } } } return true; } int main() { scanf("%d %d %d", &n, &m, &k); for (int i = 0; i < n; i++) { nodes[i].dist = INT_MAX; } nodes[0].dist = 0; for (int i = 0; i < m; i++) { int a, b, d; scanf("%d %d %d", &a, &b, &d); a--, b--; addEdge(a, b, d); // $b - $a <= d // $a + d >= $b } for (int i = 0; i < k; i++) { int a, b, d; scanf("%d %d %d", &a, &b, &d); a--, b--; addEdge(b, a, -d); // b - a >= d // a - b <= -d // b + -d >= a } if (!bellmanFord()) { puts("-1"); } else { if (nodes[n - 1].dist == INT_MAX) { puts("-2"); } else { printf("%d\n", nodes[n - 1].dist); } } return 0; }