Goldberg-Tarjan Algorithm - Continue
Goldberg-Tarjan Algorithm - Continue
Goldberg-Tarjan Algorithm - Continue
http://ocw.mit.edu
For information about citing these materials or our Terms of Use, visit: http://ocw.mit.edu/terms.
18.415/6.854 Advanced Algorithms September 17, 2008
Lecture 5
Lecturer: Michel X. Goemans
Today, we continue the discussion of the minimum cost circulation problem. We first review the
Goldberg-Tarjan algorithm, and improve it by allowing more flexibility in the selection of cycles.
This gives the Cancel-and-Tighten algorithm. We also introduce splay trees, a data structure which
we will use to create another data structure, dynamic trees, that will further improve the running
time of the algorithm.
to denote the minimum mean cost of a cycle in the residual graph Gf . In each iteration of the
algorithm, we push as much flow as possible along the minimum mean cost cycle, until µ(f ) ≥ 0.
We used �(f ) to denote the minimum � such that f is �-optimal. In other words
�(f ) = min{� : ∃ potential p : V → R such that cp (v, w) ≥ −� for all edges (v, w) ∈ Ef }.
We proved that for all circulations f ,
�(f ) = −µ(f ).
A consequence of this equality is that there exists a potential p such that any minimum mean cost
cycle Γ satisfies cp (v, w) = −�(f ) = µ(f ) for all (v, w) ∈ Γ, since the cost of each edge is bounded
below by mean cost of the cycle.
5-1
1.2 Towards a faster algorithm
In the above algorithm, a significant amount of time is used to compute the minimum cost cycle.
This is unnecessary, as our goal is simply to cancel enough edges in order to achieve a “significant”
improvement in � once every several iterations.
We can improve the algorithm by using a more flexible selection of cycles to cancel. The idea of
the Cancel-and-Tighten algorithm is to push flows along cycles consisting entirely of negative cost
edges. For a given potential p, we push as much flow as possible along cycles of this form, until no
more such cycles exist, at which point we update p and repeat.
2 Cancel-and-Tighten
2.1 Description of the Algorithm
Definition 1 An edge is admissible with respect to a potential p if cp (v, w) < 0. A cycle Γ is
admissible if all the edges of Γ are admissible.
(a) Cancel: While Gf contains a cycle Γ which is admissible with respect to p, push as much
flow as possible along Γ.
(b) Tighten: Update p to p� and � to ��� , where � �
� p and � are chosen such that cp� (v, w) ≥ −�
�
� 1
for all edges (v, w) ∈ Ef and � ≤ 1 − n �.
Remark 1 We do not update the potential p every time we push a flow. The potential p gets updated
in the tighten step after possibly several flows are pushed through in the Cancel step.
Remark 2 In the tighten step, we do not need to find p� and �� such that �� is as small as possible;
it is only necessary to decrease � by a factor of at least 1 − n1 . However, in practice, one tries to
decrease � by a smaller factor in order to obtain a better running time.
Lemma 2 Let f be a circulation and f � be the circulation obtained by performing the Cancel step.
Then we cancel at most m cycles, and
� �
1
�(f � ) ≤ 1 − �(f ).
n
Proof: Since we only cancel admissible edges, after any cycle is canceled in the Cancel step:
• All new edges in the residual graph are non-admissible, since the edge costs are skew-symmetric;
• At least one admissible edge is removed from the residual graph, since we push the maximum
possible amount of flow through the cycle.
5-2
Since we begin with at most m admissible edges, we cannot cancel more than m cycles, as each cycle
canceling reduces the number of admissible edges by at least one.
After the cancel step, every cycle Γ contains at least one non-admissible edge, say (u1 , v1 ) ∈ Γ
with cp (u1 , v1 ) ≥ 0. Then the mean cost of Γ is
� � � �
c(Γ) 1 � −(|Γ| − 1) 1 1
≥ cp (u, v) ≥ �(f ) = − 1 − �(f ) ≥ − 1 − �(f ).
|Γ| |Γ| |Γ| |Γ| n
�
(u1 ,v1 )=(u,v)∈Γ
Claim 3 The new potential function p� (v) = p(v) − l(v)�/n satisfies the property that f is �� -optimal
with respect to p� for some constant �� ≤ (1 − 1/n)�.
Case 2: l(v) > l(w), so that (v, w) is not an admissible edge. Then
5-3
2.2.2 Cancel Step
We now shift our attention to the implementation and analysis of the Cancel step. Naı̈vely, it takes
O(m) time to find a cycle in the admissible graph Ga = (V, A) (e.g., using Depth-First Search) and
push flow along it. Using a more careful implementation of the Cancel step, we shall show that each
cycle in the admissible graph can be found in an “amortized” time of O(n).
We use a Depth-First Search (DFS) approach, pushing as much flow as possible along an ad
missible cycle and removing saturated edges, as well as removing edges from the admissible graph
whenever we determine that they are not part of any cycle. Our algorithm is as follows:
Cancel(Ga = (V, A)): Choose an arbitrary vertex u ∈ V , and begin a DFS rooted at u.
1. If we reach a vertex v that has no outgoing edges, then we backtrack, deleting from A the
edges that we backtrack along, until we find an ancestor r of v for which there is another child
to explore. (Notice that every edge we backtrack along cannot be part of any cycle.) Continue
the DFS by exploring paths outgoing from r.
2. If we find a cycle Γ, then we push the maximum possible flow through it. This causes at
least one edge along Γ to be saturated. We remove the saturated edges from A, and start
the depth-first-search from scratch using G�a = (V, A� ), where A� denotes A with the saturated
edges removed.
Every edge that is not part of any cycle is visited at most twice (since it is removed from the
admissible graph the second time), so the time taken to remove edges that are not part of any cycle
is O(m). Since there are n vertices in the graph, it takes O(n) time to find a cycle (excluding the
time taken to traverse edges that are not part of any cycle), determine the maximum flow that
we can push through it, and update the flow in each of its edges. Since at least one edge of A is
saturated and removed every time we find a cycle, it follows that we find at most m cycles. Hence,
the total running time of the Cancel step is O(m + mn) = O(mn).
5-4
Operations on a BST. Here are some operations typically supported by a BST:
• Find(k): Determines whether the BST contains an object x with key[x] = k; if so, returns the
object, and if not, returns false.
• Min: Finds the node with the minimum key from the tree.
• Max: Finds the node with the minimum key from the tree.
• Successor(x): Find the node with the smallest key greater than key[x].
• Predecessor(x): Find the node with the greatest key less than key[x].
• Split(x): Returns two BSTs: one containing all the nodes y where key[y] < key[x], and the
other containing all the nodes z where key[z] ≥ key[x].
• Join(T1 , x, T2 ): Given two BSTs T1 and T2 , where all the keys in T1 are at most key[x], and
all the keys in T2 are at least key[x], returns a BST containing T1 , x and T2 .
For example, the procedure Find(k) can be implemented by traversing through the tree, and
branching to the left (resp. right) if the current node has key greater than (resp. less than) k. The
running time for many of these operations is linear in the height of the tree, which can be as high
as O(n) in the worst case, where n is the number of nodes in the tree.
A balanced BST is a BST whose height is maintained at O(log n), so that the above operations
can be run in O(log n) time. Examples of BSTs include Red-Black trees, AVL trees, and B-trees.
In the next lecture, we will discuss a data structure called splay trees, which is a self-balancing
BST with amortized cost of O(log n) per operation. The idea is that every time a node is accessed,
it gets pushed up to the root of the tree.
The basic operations of a splay tree are rotations. They are illustrated the following diagram.
y x
A B B C
5-5