Push–relabel maximum flow algorithm
Template:Short description In mathematical optimization, the push–relabel algorithm (alternatively, preflow–push algorithm) is an algorithm for computing maximum flows in a flow network. The name "push–relabel" comes from the two basic operations used in the algorithm. Throughout its execution, the algorithm maintains a "preflow" and gradually converts it into a maximum flow by moving flow locally between neighboring nodes using push operations under the guidance of an admissible network maintained by relabel operations. In comparison, the Ford–Fulkerson algorithm performs global augmentations that send flow following paths from the source all the way to the sink.[1]
The push–relabel algorithm is considered one of the most efficient maximum flow algorithms. The generic algorithm has a strongly polynomial O(V 2E)Script error: No such module "Check for unknown parameters". time complexity, which is asymptotically more efficient than the O(VE 2)Script error: No such module "Check for unknown parameters". Edmonds–Karp algorithm.[2] Specific variants of the algorithms achieve even lower time complexities. The variant based on the highest label node selection rule has O(V 2
- REDIRECT Template:Radic
Template:Rcat shell)Script error: No such module "Check for unknown parameters". time complexity and is generally regarded as the benchmark for maximum flow algorithms.[3][4] Subcubic O(VElog(V 2/E))Script error: No such module "Check for unknown parameters". time complexity can be achieved using dynamic trees,[2] although in practice it is less efficient.Script error: No such module "Unsubst".
The push–relabel algorithm has been extended to compute minimum cost flows.[5] The idea of distance labels has led to a more efficient augmenting path algorithm, which in turn can be incorporated back into the push–relabel algorithm to create a variant with even higher empirical performance.[4][6]
History
The concept of a preflow was originally designed by Alexander V. Karzanov and was published in 1974 in Soviet Mathematical Dokladi 15. This pre-flow algorithm also used a push operation; however, it used distances in the auxiliary network to determine where to push the flow instead of a labeling system.[2][7]
The push-relabel algorithm was designed by Andrew V. Goldberg and Robert Tarjan. The algorithm was initially presented in November 1986 in STOC '86: Proceedings of the eighteenth annual ACM symposium on Theory of computing, and then officially in October 1988 as an article in the Journal of the ACM. Both papers detail a generic form of the algorithm terminating in O(V 2E)Script error: No such module "Check for unknown parameters". along with a O(V 3)Script error: No such module "Check for unknown parameters". sequential implementation, a O(VE log(V 2/E))Script error: No such module "Check for unknown parameters". implementation using dynamic trees, and parallel/distributed implementation.[2][8] As explained in,[9] Goldberg-Tarjan introduced distance labels by incorporating them into the parallel maximum flow algorithm of Yossi Shiloach and Uzi Vishkin.[10]
Concepts
Definitions and notations
Script error: No such module "Labelled list hatnote".
Let:
- G = (V, E)Script error: No such module "Check for unknown parameters". be a network with capacity function c: V × V → ∞Script error: No such module "Check for unknown parameters".,
- F = (G, c, s, t)Script error: No such module "Check for unknown parameters". a flow network, where s ∈ VScript error: No such module "Check for unknown parameters". and t ∈ VScript error: No such module "Check for unknown parameters". are chosen source and sink vertices respectively,
- f : V × V → Script error: No such module "Check for unknown parameters". denote a pre-flow in Template:Mvar,
- xf : V → Script error: No such module "Check for unknown parameters". denote the excess function with respect to the flow Template:Mvar, defined by xf (u) = Σv ∈ V f (v, u) − Σv ∈ V f (u, v)Script error: No such module "Check for unknown parameters".,
- cf : V × V → ∞Script error: No such module "Check for unknown parameters". denote the residual capacity function with respect to the flow Template:Mvar, defined by cf (e) = c(e) − f (e)Script error: No such module "Check for unknown parameters".,
- Ef ⊂ EScript error: No such module "Check for unknown parameters". being the edges where f < cScript error: No such module "Check for unknown parameters".,
and
- Gf (V, Ef )Script error: No such module "Check for unknown parameters". denote the residual network of Template:Mvar with respect to the flow Template:Mvar.
The push–relabel algorithm uses a nonnegative integer valid labeling function which makes use of distance labels, or heights, on nodes to determine which arcs should be selected for the push operation. This labeling function is denoted by 𝓁 : V → Script error: No such module "Check for unknown parameters".. This function must satisfy the following conditions in order to be considered valid:
- Valid labeling:
- 𝓁(u) ≤ 𝓁(v) + 1Script error: No such module "Check for unknown parameters". for all (u, v) ∈ EfScript error: No such module "Check for unknown parameters".
- Source condition:
- 𝓁(s) = | V |Script error: No such module "Check for unknown parameters".
- Sink conservation:
- 𝓁(t) = 0Script error: No such module "Check for unknown parameters".
In the algorithm, the label values of Template:Mvar and Template:Mvar are fixed. 𝓁(u)Script error: No such module "Check for unknown parameters". is a lower bound of the unweighted distance from Template:Mvar to Template:Mvar in GfScript error: No such module "Check for unknown parameters". if Template:Mvar is reachable from Template:Mvar. If Template:Mvar has been disconnected from Template:Mvar, then 𝓁(u) − | V |Script error: No such module "Check for unknown parameters". is a lower bound of the unweighted distance from Template:Mvar to Template:Mvar. As a result, if a valid labeling function exists, there are no s-tScript error: No such module "Check for unknown parameters". paths in GfScript error: No such module "Check for unknown parameters". because no such paths can be longer than | V | − 1Script error: No such module "Check for unknown parameters"..
An arc (u, v) ∈ EfScript error: No such module "Check for unknown parameters". is called admissible if 𝓁(u) = 𝓁(v) + 1Script error: No such module "Check for unknown parameters".. The admissible network G̃f (V, Ẽf )Script error: No such module "Check for unknown parameters". is composed of the set of arcs e ∈ EfScript error: No such module "Check for unknown parameters". that are admissible. The admissible network is acyclic.
For a fixed flow fScript error: No such module "Check for unknown parameters"., a vertex v ∉ {s, t} Script error: No such module "Check for unknown parameters". is called active if it has positive excess with respect to fScript error: No such module "Check for unknown parameters"., i.e., xf (u) > 0Script error: No such module "Check for unknown parameters"..
Operations
Initialization
The algorithm starts by creating a residual graph, initializing the preflow values to zero and performing a set of saturating push operations on residual arcs (s, v)Script error: No such module "Check for unknown parameters". exiting the source, where v ∈ V \ {s}Script error: No such module "Check for unknown parameters".. Similarly, the labels are initialized such that the label at the source is the number of nodes in the graph, 𝓁(s) = | V |Script error: No such module "Check for unknown parameters"., and all other nodes are given a label of zero. Once the initialization is complete the algorithm repeatedly performs either the push or relabel operations against active nodes until no applicable operation can be performed.
Push
The push operation applies on an admissible out-arc (u, v)Script error: No such module "Check for unknown parameters". of an active node Template:Mvar in GfScript error: No such module "Check for unknown parameters".. It moves min{xf (u), cf (u,v)}Script error: No such module "Check for unknown parameters". units of flow from Template:Mvar to Template:Mvar.
push(u, v):
assert xf[u] > 0 and 𝓁[u] == 𝓁[v] + 1
Δ = min(xf[u], c[u][v] - f[u][v])
f[u][v] += Δ
f[v][u] -= Δ
xf[u] -= Δ
xf[v] += Δ
A push operation that causes f (u, v)Script error: No such module "Check for unknown parameters". to reach c(u, v)Script error: No such module "Check for unknown parameters". is called a saturating push since it uses up all the available capacity of the residual arc. Otherwise, all of the excess at the node is pushed across the residual arc. This is called an unsaturating or non-saturating push.
Relabel
The relabel operation applies on an active node Template:Mvar which is neither the source nor the sink without any admissible out-arcs in GfScript error: No such module "Check for unknown parameters".. It modifies 𝓁(u)Script error: No such module "Check for unknown parameters". to be the minimum value such that an admissible out-arc is created. Note that this always increases 𝓁(u)Script error: No such module "Check for unknown parameters". and never creates a steep arc, which is an arc (u, v)Script error: No such module "Check for unknown parameters". such that cf (u, v) > 0Script error: No such module "Check for unknown parameters"., and 𝓁(u) > 𝓁(v) + 1Script error: No such module "Check for unknown parameters"..
relabel(u):
assert xf[u] > 0 and 𝓁[u] <= 𝓁[v] for all v such that cf[u][v] > 0
𝓁[u] = 1 + min(𝓁[v] for all v such that cf[u][v] > 0)
Effects of push and relabel
After a push or relabel operation, 𝓁Script error: No such module "Check for unknown parameters". remains a valid labeling function with respect to Template:Mvar.
For a push operation on an admissible arc (u, v)Script error: No such module "Check for unknown parameters"., it may add an arc (v, u)Script error: No such module "Check for unknown parameters". to EfScript error: No such module "Check for unknown parameters"., where 𝓁(v) = 𝓁(u) − 1 ≤ 𝓁(u) + 1Script error: No such module "Check for unknown parameters".; it may also remove the arc (u, v)Script error: No such module "Check for unknown parameters". from EfScript error: No such module "Check for unknown parameters"., where it effectively removes the constraint 𝓁(u) ≤ 𝓁(v) + 1Script error: No such module "Check for unknown parameters"..
To see that a relabel operation on node Template:Mvar preserves the validity of 𝓁(u)Script error: No such module "Check for unknown parameters"., notice that this is trivially guaranteed by definition for the out-arcs of u in GfScript error: No such module "Check for unknown parameters".. For the in-arcs of Template:Mvar in GfScript error: No such module "Check for unknown parameters"., the increased 𝓁(u)Script error: No such module "Check for unknown parameters". can only satisfy the constraints less tightly, not violate them.
The generic push–relabel algorithm
The generic push–relabel algorithm is used as a proof of concept only and does not contain implementation details on how to select an active node for the push and relabel operations. This generic version of the algorithm will terminate in O(V2E)Script error: No such module "Check for unknown parameters"..
Since 𝓁(s) = | V |Script error: No such module "Check for unknown parameters"., 𝓁(t) = 0Script error: No such module "Check for unknown parameters"., and there are no paths longer than | V | − 1Script error: No such module "Check for unknown parameters". in GfScript error: No such module "Check for unknown parameters"., in order for 𝓁(s)Script error: No such module "Check for unknown parameters". to satisfy the valid labeling condition Template:Mvar must be disconnected from Template:Mvar. At initialisation, the algorithm fulfills this requirement by creating a pre-flow Template:Mvar that saturates all out-arcs of Template:Mvar, after which 𝓁(v) = 0Script error: No such module "Check for unknown parameters". is trivially valid for all v ∈ V \ {s, t}Script error: No such module "Check for unknown parameters".. After initialisation, the algorithm repeatedly executes an applicable push or relabel operation until no such operations apply, at which point the pre-flow has been converted into a maximum flow.
generic-push-relabel(G, c, s, t):
create a pre-flow f that saturates all out-arcs of s
let 𝓁[s] = |V|
let 𝓁[v] = 0 for all v ∈ V \ {s}
while there is an applicable push or relabel operation do
execute the operation
Correctness
The algorithm maintains the condition that 𝓁Script error: No such module "Check for unknown parameters". is a valid labeling during its execution. This can be proven true by examining the effects of the push and relabel operations on the label function 𝓁Script error: No such module "Check for unknown parameters".. The relabel operation increases the label value by the associated minimum plus one which will always satisfy the 𝓁(u) ≤ 𝓁(v) + 1Script error: No such module "Check for unknown parameters". constraint. The push operation can send flow from Template:Mvar to Template:Mvar if 𝓁(u) = 𝓁(v) + 1Script error: No such module "Check for unknown parameters".. This may add (v, u)Script error: No such module "Check for unknown parameters". to Gf Script error: No such module "Check for unknown parameters". and may delete (u, v)Script error: No such module "Check for unknown parameters". from Gf Script error: No such module "Check for unknown parameters".. The addition of (v, u)Script error: No such module "Check for unknown parameters". to Gf Script error: No such module "Check for unknown parameters". will not affect the valid labeling since 𝓁(v) = 𝓁(u) − 1Script error: No such module "Check for unknown parameters".. The deletion of (u, v)Script error: No such module "Check for unknown parameters". from Gf Script error: No such module "Check for unknown parameters". removes the corresponding constraint since the valid labeling property 𝓁(u) ≤ 𝓁(v) + 1Script error: No such module "Check for unknown parameters". only applies to residual arcs in Gf Script error: No such module "Check for unknown parameters"..[8]
If a preflow Template:Mvar and a valid labeling 𝓁Script error: No such module "Check for unknown parameters". for Template:Mvar exists then there is no augmenting path from Template:Mvar to Template:Mvar in the residual graph Gf Script error: No such module "Check for unknown parameters".. This can be proven by contradiction based on inequalities which arise in the labeling function when supposing that an augmenting path does exist. If the algorithm terminates, then all nodes in V \ {s, t}Script error: No such module "Check for unknown parameters". are not active. This means all v ∈ V \ {s, t}Script error: No such module "Check for unknown parameters". have no excess flow, and with no excess the preflow Template:Mvar obeys the flow conservation constraint and can be considered a normal flow. This flow is the maximum flow according to the max-flow min-cut theorem since there is no augmenting path from Template:Mvar to Template:Mvar.[8]
Therefore, the algorithm will return the maximum flow upon termination.
Time complexity
In order to bound the time complexity of the algorithm, we must analyze the number of push and relabel operations which occur within the main loop. The numbers of relabel, saturating push and nonsaturating push operations are analyzed separately.
In the algorithm, the relabel operation can be performed at most (2| V | − 1)(| V | − 2) < 2| V |2Script error: No such module "Check for unknown parameters". times. This is because the labeling 𝓁(u)Script error: No such module "Check for unknown parameters". value for any node u can never decrease, and the maximum label value is at most 2| V | − 1Script error: No such module "Check for unknown parameters". for all nodes. This means the relabel operation could potentially be performed 2| V | − 1 Script error: No such module "Check for unknown parameters". times for all nodes V \ {s, t}Script error: No such module "Check for unknown parameters". (i.e. | V | − 2Script error: No such module "Check for unknown parameters".). This results in a bound of O(V 2)Script error: No such module "Check for unknown parameters". for the relabel operation.
Each saturating push on an admissible arc (u, v)Script error: No such module "Check for unknown parameters". removes the arc from Gf Script error: No such module "Check for unknown parameters".. For the arc to be reinserted into Gf Script error: No such module "Check for unknown parameters". for another saturating push, Template:Mvar must first be relabeled, followed by a push on the arc (v, u)Script error: No such module "Check for unknown parameters"., then Template:Mvar must be relabeled. In the process, 𝓁(u)Script error: No such module "Check for unknown parameters". increases by at least two. Therefore, there are O(V)Script error: No such module "Check for unknown parameters". saturating pushes on (u, v)Script error: No such module "Check for unknown parameters"., and the total number of saturating pushes is at most 2| V || E |Script error: No such module "Check for unknown parameters".. This results in a time bound of O(VE)Script error: No such module "Check for unknown parameters". for the saturating push operations.
Bounding the number of nonsaturating pushes can be achieved via a potential argument. We use the potential function Φ = Σ[u ∈ V ∧ xf (u) > 0] 𝓁(u)Script error: No such module "Check for unknown parameters". (i.e. ΦScript error: No such module "Check for unknown parameters". is the sum of the labels of all active nodes). It is obvious that ΦScript error: No such module "Check for unknown parameters". is 0Script error: No such module "Check for unknown parameters". initially and stays nonnegative throughout the execution of the algorithm. Both relabels and saturating pushes can increase ΦScript error: No such module "Check for unknown parameters".. However, the value of ΦScript error: No such module "Check for unknown parameters". must be equal to 0 at termination since there cannot be any remaining active nodes at the end of the algorithm's execution. This means that over the execution of the algorithm, the nonsaturating pushes must make up the difference of the relabel and saturating push operations in order for ΦScript error: No such module "Check for unknown parameters". to terminate with a value of 0. The relabel operation can increase ΦScript error: No such module "Check for unknown parameters". by at most (2| V | − 1)(| V | − 2)Script error: No such module "Check for unknown parameters".. A saturating push on (u, v)Script error: No such module "Check for unknown parameters". activates Template:Mvar if it was inactive before the push, increasing ΦScript error: No such module "Check for unknown parameters". by at most 2| V | − 1Script error: No such module "Check for unknown parameters".. Hence, the total contribution of all saturating pushes operations to ΦScript error: No such module "Check for unknown parameters". is at most (2| V | − 1)(2| V || E |)Script error: No such module "Check for unknown parameters".. A nonsaturating push on (u, v)Script error: No such module "Check for unknown parameters". always deactivates Template:Mvar, but it can also activate Template:Mvar as in a saturating push. As a result, it decreases ΦScript error: No such module "Check for unknown parameters". by at least 𝓁(u) − 𝓁(v) = 1Script error: No such module "Check for unknown parameters".. Since relabels and saturating pushes increase ΦScript error: No such module "Check for unknown parameters"., the total number of nonsaturating pushes must make up the difference of (2| V | − 1)(| V | − 2) + (2| V | − 1)(2| V || E |) ≤ 4| V |2| E |Script error: No such module "Check for unknown parameters".. This results in a time bound of O(V 2E)Script error: No such module "Check for unknown parameters". for the nonsaturating push operations.
In sum, the algorithm executes O(V 2)Script error: No such module "Check for unknown parameters". relabels, O(VE)Script error: No such module "Check for unknown parameters". saturating pushes and O(V 2E)Script error: No such module "Check for unknown parameters". nonsaturating pushes. Data structures can be designed to pick and execute an applicable operation in O(1)Script error: No such module "Check for unknown parameters". time. Therefore, the time complexity of the algorithm is O(V 2E)Script error: No such module "Check for unknown parameters"..[1][8]
Example
The following is a sample execution of the generic push-relabel algorithm, as defined above, on the following simple network flow graph diagram.
Script error: No such module "Multiple image".
In the example, the h and e values denote the label 𝓁Script error: No such module "Check for unknown parameters". and excess xf Script error: No such module "Check for unknown parameters"., respectively, of the node during the execution of the algorithm. Each residual graph in the example only contains the residual arcs with a capacity larger than zero. Each residual graph may contain multiple iterations of the perform operation loop.
| Algorithm Operation(s) | Residual Graph |
|---|---|
| Initialise the residual graph by setting the preflow to values 0 and initialising the labeling. | Step 1 |
| Initial saturating push is performed across all preflow arcs out of the source, Template:Mvar. | Step 2 |
| Node Template:Mvar is relabeled in order to push its excess flow towards the sink, Template:Mvar.
The excess at Template:Mvar is then pushed to Template:Mvar then Template:Mvar in two subsequent saturating pushes; which still leaves Template:Mvar with some excess. | |
| Step 3 | |
| Once again, Template:Mvar is relabeled in order to push its excess along its last remaining positive residual (i.e. push the excess back to Template:Mvar).
The node Template:Mvar is then removed from the set of active nodes. | |
| Step 4 | |
| Relabel Template:Mvar and then push its excess to Template:Mvar and Template:Mvar. | Step 5 |
| Relabel Template:Mvar and then push its excess to Template:Mvar. | Step 6 |
| Relabel Template:Mvar and then push its excess to Template:Mvar. | Step 7 |
| This leaves the node Template:Mvar as the only remaining active node, but it cannot push its excess flow towards the sink.
Relabel Template:Mvar and then push its excess towards the source, Template:Mvar, via the node Template:Mvar. | |
| Step 8 | |
| Push the last bit of excess at Template:Mvar back to the source, Template:Mvar.
There are no remaining active nodes. The algorithm terminates and returns the maximum flow of the graph (as seen above). | |
| Step 9 |
The example (but with initial flow of 0) can be run here interactively.
Practical implementations
While the generic push–relabel algorithm has O(V 2E)Script error: No such module "Check for unknown parameters". time complexity, efficient implementations achieve O(V 3)Script error: No such module "Check for unknown parameters". or lower time complexity by enforcing appropriate rules in selecting applicable push and relabel operations. The empirical performance can be further improved by heuristics.
"Current-arc" data structure and discharge operation
The "current-arc" data structure is a mechanism for visiting the in- and out-neighbors of a node in the flow network in a static circular order. If a singly linked list of neighbors is created for a node, the data structure can be as simple as a pointer into the list that steps through the list and rewinds to the head when it runs off the end.
Based on the "current-arc" data structure, the discharge operation can be defined. A discharge operation applies on an active node and repeatedly pushes flow from the node until it becomes inactive, relabeling it as necessary to create admissible arcs in the process.
discharge(u):
while xf[u] > 0 do
if current-arc[u] has run off the end of neighbors[u] then
relabel(u)
rewind current-arc[u]
else
let (u, v) = current-arc[u]
if (u, v) is admissible then
push(u, v)
let current-arc[u] point to the next neighbor of u
Finding the next admissible edge to push on has amortized complexity. The current-arc pointer only moves to the next neighbor when the edge to the current neighbor is saturated or non-admissible, and neither of these two properties can change until the active node is relabelled. Therefore, when the pointer runs off, there are no admissible unsaturated edges and we have to relabel the active node , so having moved the pointer times is paid for by the relabel operation.[8]
Active node selection rules
Definition of the discharge operation reduces the push–relabel algorithm to repeatedly selecting an active node to discharge. Depending on the selection rule, the algorithm exhibits different time complexities. For the sake of brevity, we ignore Template:Mvar and Template:Mvar when referring to the nodes in the following discussion.
FIFO selection rule
The FIFO push–relabel algorithm[2] organizes the active nodes into a queue. The initial active nodes can be inserted in arbitrary order. The algorithm always removes the node at the front of the queue for discharging. Whenever an inactive node becomes active, it is appended to the back of the queue.
The algorithm has O(V 3)Script error: No such module "Check for unknown parameters". time complexity.
Relabel-to-front selection rule
The relabel-to-front push–relabel algorithm[1] organizes all nodes into a linked list and maintains the invariant that the list is topologically sorted with respect to the admissible network. The algorithm scans the list from front to back and performs a discharge operation on the current node if it is active. If the node is relabeled, it is moved to the front of the list, and the scan is restarted from the front.
The algorithm also has O(V 3)Script error: No such module "Check for unknown parameters". time complexity.
Highest label selection rule
The highest-label push–relabel algorithm[11] organizes all nodes into buckets indexed by their labels. The algorithm always selects an active node with the largest label to discharge.
The algorithm has O(V 2
- REDIRECT Template:Radic
Template:Rcat shell)Script error: No such module "Check for unknown parameters". time complexity. If the lowest-label selection rule is used instead, the time complexity becomes O(V 2E)Script error: No such module "Check for unknown parameters"..[3]
Implementation techniques
Although in the description of the generic push–relabel algorithm above, 𝓁(u)Script error: No such module "Check for unknown parameters". is set to zero for each node u other than Template:Mvar and Template:Mvar at the beginning, it is preferable to perform a backward breadth-first search from Template:Mvar to compute exact labels.[2]
The algorithm is typically separated into two phases. Phase one computes a maximum pre-flow by discharging only active nodes whose labels are below Template:Mvar. Phase two converts the maximum preflow into a maximum flow by returning excess flow that cannot reach Template:Mvar to Template:Mvar. It can be shown that phase two has O(VE)Script error: No such module "Check for unknown parameters". time complexity regardless of the order of push and relabel operations and is therefore dominated by phase one. Alternatively, it can be implemented using flow decomposition.[9]
Heuristics are crucial to improving the empirical performance of the algorithm.[12] Two commonly used heuristics are the gap heuristic and the global relabeling heuristic.[2][13] The gap heuristic detects gaps in the labeling function. If there is a label 0 < 𝓁Template:' < | V | for which there is no node Template:Mvar such that 𝓁(u) = 𝓁Template:'Script error: No such module "Check for unknown parameters"., then any node Template:Mvar with 𝓁Template:' < 𝓁(u) < | V |Script error: No such module "Check for unknown parameters". has been disconnected from Template:Mvar and can be relabeled to (| V | + 1)Script error: No such module "Check for unknown parameters". immediately. The global relabeling heuristic periodically performs backward breadth-first search from Template:Mvar in Gf Script error: No such module "Check for unknown parameters". to compute the exact labels of the nodes. Both heuristics skip unhelpful relabel operations, which are a bottleneck of the algorithm and contribute to the ineffectiveness of dynamic trees.[4]
Sample implementations
<templatestyles src="Template:Hidden begin/styles.css"/>
#include <stdlib.h>
#include <stdio.h>
#define NODES 6
#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))
#define INFINITE 10000000
void push(const int * const * C, int ** F, int *excess, int u, int v) {
int send = MIN(excess[u], C[u][v] - F[u][v]);
F[u][v] += send;
F[v][u] -= send;
excess[u] -= send;
excess[v] += send;
}
void relabel(const int * const * C, const int * const * F, int *height, int u) {
int v;
int min_height = INFINITE;
for (v = 0; v < NODES; v++) {
if (C[u][v] - F[u][v] > 0) {
min_height = MIN(min_height, height[v]);
height[u] = min_height + 1;
}
}
};
void discharge(const int * const * C, int ** F, int *excess, int *height, int *seen, int u) {
while (excess[u] > 0) {
if (seen[u] < NODES) {
int v = seen[u];
if ((C[u][v] - F[u][v] > 0) && (height[u] > height[v])) {
push(C, F, excess, u, v);
} else {
seen[u] += 1;
}
} else {
relabel(C, F, height, u);
seen[u] = 0;
}
}
}
void moveToFront(int i, int *A) {
int temp = A[i];
int n;
for (n = i; n > 0; n--) {
A[n] = A[n-1];
}
A[0] = temp;
}
int pushRelabel(const int * const * C, int ** F, int source, int sink) {
int *excess, *height, *list, *seen, i, p;
excess = (int *) calloc(NODES, sizeof(int));
height = (int *) calloc(NODES, sizeof(int));
seen = (int *) calloc(NODES, sizeof(int));
list = (int *) calloc((NODES-2), sizeof(int));
for (i = 0, p = 0; i < NODES; i++){
if ((i != source) && (i != sink)) {
list[p] = i;
p++;
}
}
height[source] = NODES;
excess[source] = INFINITE;
for (i = 0; i < NODES; i++)
push(C, F, excess, source, i);
p = 0;
while (p < NODES - 2) {
int u = list[p];
int old_height = height[u];
discharge(C, F, excess, height, seen, u);
if (height[u] > old_height) {
moveToFront(p, list);
p = 0;
} else {
p += 1;
}
}
int maxflow = 0;
for (i = 0; i < NODES; i++)
maxflow += F[source][i];
free(list);
free(seen);
free(height);
free(excess);
return maxflow;
}
void printMatrix(const int * const * M) {
int i, j;
for (i = 0; i < NODES; i++) {
for (j = 0; j < NODES; j++)
printf("%d\t",M[i][j]);
printf("\n");
}
}
int main(void) {
int **flow, **capacities, i;
flow = (int **) calloc(NODES, sizeof(int*));
capacities = (int **) calloc(NODES, sizeof(int*));
for (i = 0; i < NODES; i++) {
flow[i] = (int *) calloc(NODES, sizeof(int));
capacities[i] = (int *) calloc(NODES, sizeof(int));
}
// Sample graph
capacities[0][1] = 2;
capacities[0][2] = 9;
capacities[1][2] = 1;
capacities[1][3] = 0;
capacities[1][4] = 0;
capacities[2][4] = 7;
capacities[3][5] = 7;
capacities[4][5] = 4;
printf("Capacity:\n");
printMatrix(capacities);
printf("Max Flow:\n%d\n", pushRelabel(capacities, flow, 0, 5));
printf("Flows:\n");
printMatrix(flow);
return 0;
}
<templatestyles src="Template:Hidden begin/styles.css"/>
def relabel_to_front(C, source: int, sink: int) -> int:
n = len(C) # C is the capacity matrix
F = [[0] * n for _ in range(n)]
# residual capacity from u to v is C[u][v] - F[u][v]
height = [0] * n # height of node
excess = [0] * n # flow into node minus flow from node
seen = [0] * n # neighbours seen since last relabel
# node "queue"
nodelist = [i for i in range(n) if i != source and i != sink]
def push(u, v):
send = min(excess[u], C[u][v] - F[u][v])
F[u][v] += send
F[v][u] -= send
excess[u] -= send
excess[v] += send
def relabel(u):
# Find smallest new height making a push possible,
# if such a push is possible at all.
min_height = ∞
for v in range(n):
if C[u][v] - F[u][v] > 0:
min_height = min(min_height, height[v])
height[u] = min_height + 1
def discharge(u):
while excess[u] > 0:
if seen[u] < n: # check next neighbour
v = seen[u]
if C[u][v] - F[u][v] > 0 and height[u] > height[v]:
push(u, v)
else:
seen[u] += 1
else: # we have checked all neighbours. must relabel
relabel(u)
seen[u] = 0
height[source] = n # longest path from source to sink is less than n long
excess[source] = ∞ # send as much flow as possible to neighbours of source
for v in range(n):
push(source, v)
p = 0
while p < len(nodelist):
u = nodelist[p]
old_height = height[u]
discharge(u)
if height[u] > old_height:
nodelist.insert(0, nodelist.pop(p)) # move to front of list
p = 0 # start from front of list
else:
p += 1
return sum(F[source])
References
<templatestyles src="Reflist/styles.css" />
- ↑ a b c Script error: No such module "citation/CS1".
- ↑ a b c d e f g Script error: No such module "citation/CS1".
- ↑ a b Script error: No such module "Citation/CS1".
- ↑ a b c Script error: No such module "citation/CS1".
- ↑ Script error: No such module "Citation/CS1".
- ↑ Script error: No such module "Citation/CS1".
- ↑ Script error: No such module "Citation/CS1".
- ↑ a b c d e Script error: No such module "Citation/CS1".
- ↑ a b Script error: No such module "citation/CS1".
- ↑ Script error: No such module "Citation/CS1".
- ↑ Script error: No such module "citation/CS1".
- ↑ Script error: No such module "citation/CS1".
- ↑ Script error: No such module "Citation/CS1".
Script error: No such module "Check for unknown parameters".