Definition
A system of difference constraints is a special system of linear inequalities in n variables. It contains variables and constraints. Each constraint is formed by taking the difference of two variables, in the form , where , and is a constant (which may be nonnegative or negative). The problem is to find a solution satisfying all constraints, or determine that no solution exists.
Every constraint in a system of difference constraints can be transformed into , which is very similar to the triangle inequality in the single-source shortest-path problem. Therefore, we can regard each variable as a vertex in a graph and, for each constraint , add a directed edge of length from vertex to vertex .
Note that if is a solution to the system of difference constraints, then for any constant , is clearly also a solution, because cancels out when taking differences.
Process
Set and add an edge of weight from vertex 0 to every other vertex. Run a single-source shortest-path algorithm. If the graph contains a negative cycle, the given system of difference constraints has no solution; otherwise, is a solution to the system.
Properties
Bellman–Ford or its queue-optimized version (commonly called SPFA, which can be very fast on some random graphs) is generally used to determine whether the graph contains a negative cycle. Its worst-case time complexity is .
Common transformation techniques
Example Luogu P1993 Little K's Farm
Problem statement: solve a system of difference constraints with constraints, each of which has the form , , or , and determine whether the system has a solution.
| Meaning | Transformation | Added edge |
|---|---|---|
add(a, b, -c); | ||
add(b, a, c); | ||
add(b, a, 0), add(a, b, 0); |
Run the negative-cycle check. If there is no negative cycle, output Yes; otherwise, output No.
Reference code
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
struct edge {
int v, w, next;
} e[40005];
int head[10005], vis[10005], tot[10005], cnt;
long long ans, dist[10005];
queue<int> q;
void addedge(int u, int v, int w) { // add an edge
e[++cnt].v = v;
e[cnt].w = w;
e[cnt].next = head[u];
head[u] = cnt;
}
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int n, m;
cin >> n >> m;
for (int i = 1; i <= m; i++) {
int op, x, y, z;
cin >> op;
if (op == 1) {
cin >> x >> y >> z;
addedge(y, x, z);
} else if (op == 2) {
cin >> x >> y >> z;
addedge(x, y, -z);
} else {
cin >> x >> y;
addedge(x, y, 0);
addedge(y, x, 0);
}
}
for (int i = 1; i <= n; i++) addedge(0, i, 0);
memset(dist, -0x3f, sizeof(dist));
dist[0] = 0;
vis[0] = 1;
q.push(0);
while (!q.empty()) { // detect negative cycles; see above
int cur = q.front();
q.pop();
vis[cur] = 0;
for (int i = head[cur]; i; i = e[i].next)
if (dist[cur] + e[i].w > dist[e[i].v]) {
dist[e[i].v] = dist[cur] + e[i].w;
if (!vis[e[i].v]) {
vis[e[i].v] = 1;
q.push(e[i].v);
tot[e[i].v]++;
if (tot[e[i].v] >= n) {
cout << "No\n";
return 0;
}
}
}
}
cout << "Yes\n";
return 0;
}
Example P4926 [1007] Multiplier
Ignoring binary search and other details, here we discuss only how to solve the difference system .
Taking a of each and turns multiplication into addition: , which can then be solved using difference constraints.
Bellman–Ford implementation for detecting negative cycles
The following is an implementation of the Bellman–Ford algorithm for determining whether a graph contains a negative cycle. Before calling it, ensure that the graph is connected.
Implementation
C++
bool Bellman_Ford() {
for (int i = 0; i < n; i++) {
bool jud = false;
for (int j = 1; j <= n; j++)
for (int k = h[j]; ~k; k = nxt[k])
if (dist[j] > dist[p[k]] + w[k])
dist[j] = dist[p[k]] + w[k], jud = true;
if (!jud) break;
}
for (int i = 1; i <= n; i++)
for (int j = h[i]; ~j; j = nxt[j])
if (dist[i] > dist[p[j]] + w[j]) return false;
return true;
}
Python
def Bellman_Ford():
for i in range(0, n):
jud = False
for j in range(1, n + 1):
while ~k:
k = h[j]
if dist[j] > dist[p[k]] + w[k]:
dist[j] = dist[p[k]] + w[k]
jud = True
k = nxt[k]
if jud == False:
break
for i in range(1, n + 1):
while ~j:
j = h[i]
if dist[i] > dist[p[j]] + w[j]:
return False
j = nxt[j]
return True