Difference constraints
Turn a system of inequalities x_j − x_i ≤ b into a graph and solve it with Bellman–Ford: the shortest-path distances are a solution, and a negative cycle means there is none.
We have a system of inequalities of the form x_j − x_i ≤ b (in scheduling, say: "job j starts at most b units after
job i"). We want values for x that satisfy them all, or to learn that none exist.
- Time:
O(n · m) - Space:
O(n + m) - CLRS, section 22.4
Eight constraints on five variables (the CLRS example); one solution: x = (−5, −3, 0, −1, −4).
def difference_constraints(C):# Each row [j, i, b] means x_j - x_i <= b: an edge i -> j of weight b. Vertex 0 is a source with 0-edges to all.n = 0for j, i, b in C:n = max(n, i, j)edges = []for v in range(1, n + 1):edges.append([0, v, 0])for j, i, b in C:edges.append([i, j, b])x = [0] + [float("inf")] * nfor rnd in range(1, n + 1):changed = Falsefor u, v, w in edges:if x[u] + w < x[v]:x[v] = x[u] + wchanged = Trueif not changed:breakfor u, v, w in edges:if x[u] + w < x[v]:return Nonesolution = x[1:]return solution
Start
Local variables
Orange = changed in this step
C list
Call stack
- difference_constraints()line 1
Explanation
The problem
We have a system of inequalities of the form x_j − x_i ≤ b (in scheduling, say: "job j starts at most b units after
job i"). We want values for x that satisfy them all, or to learn that none exist.
Turning it into shortest paths
Each constraint x_j − x_i ≤ b is an edge i → j of weight b; it is exactly the shortest-path condition
d(j) ≤ d(i) + w(i, j). Add a source vertex 0 with a weight-0 edge to every variable. Now:
- if the graph has no negative cycle,
x_i = δ(0, i)is a solution; - if it has one, adding up the constraints around the cycle gives
0 ≤ a negative number: there is no solution.
Bellman–Ford tells the two apart: O(n·m).
A note
If x is a solution, so is x + c; this algorithm gives the solution with every x_i ≤ 0 and the largest sum.
The input
Each row [j, i, b] means x_j − x_i ≤ b; the variables are numbered from 1.