若是一個系統由 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; }