Wikipedia / Hopcroft–Karp algorithm
Wikipedia / Hopcroft–Karp algorithm
In computer science, the Hopcroft–Karp algorithm (sometimes more accurately called the Hopcroft–Karp–Karzanov algorithm) is an algorithm that takes a bipartite graph as input and produces a maximum-cardinality matching time in the worst case. In the case of dense graphs, and for sparse random graphs with high probability.
The algorithm was discovered by and independently by . As in previous methods for matching such as the Hungarian algorithm and the work of , the Hopcroft–Karp algorithm repeatedly increases the size of a partial matching by finding augmenting paths. These paths are sequences of edges of the graph, which alternate between edges in the matching and edges out of the partial matching, and where the initial and final edge are not in the partial matching. Finding an augmenting path allows us to increment the size of the partial matching, by simply toggling the edges of the augmenting path (putting in the partial matching those that were not, and vice versa). Simpler algorithms for bipartite matching, such as the Ford–Fulkerson algorithm can be achieved to find maximum-cardinality matchings in arbitrary graphs, with the more complicated algorithm of Micali and Vazirani.
The Hopcroft–Karp algorithm can be seen as a special case of Dinic's algorithm for the maximum-flow problem.
Augmenting paths
is called a free vertex. The basic concept that the algorithm relies on is that of an augmenting path, a path that starts at a free vertex, ends at a free vertex, and alternates between unmatched and matched edges within the path. It follows from this definition that, except for the endpoints, all other vertices (if any) in augmenting path must be non-free vertices. An augmenting path could consist of only two vertices (both free) and single unmatched edge between them.
, then the symmetric difference. Thus, by finding augmenting paths, an algorithm may increase the size of the matching.
is an optimal matching must be optimal.
An augmenting path in a matching problem is closely related to the augmenting paths arising in maximum flow problems have unit capacity. A generalization of the technique used in Hopcroft–Karp algorithm to find maximum flow in an arbitrary network is known as Dinic's algorithm.
Algorithm
The algorithm may be expressed in the following pseudocode.
Input
Output
repeat
maximal set of vertex-disjoint shortest augmenting paths
until
. The algorithm is run in phases. Each phase consists of the following steps.
A breadth-first search partitions the vertices of the graph into layers.
are by definition not adjacent to any matched edges.
only matched edges may be traversed.
are reached.
Because every path which reaches a matched node proceeds immediately to its partner in the matching, some implementations assign the same depth to both vertices, only incrementing the depth when traversing an unmatched edge.
if and only if it ends a shortest augmenting path.
The algorithm finds a maximal set of vertex disjoint. (Maximal means that no more such paths can be added. This is different from finding the maximum number of such paths, which would be harder to do. Fortunately, it is sufficient here to find a maximal set of paths.)
This set may be computed by depth-first search, using the breadth first layering to guide the search: the DFS is only allowed to follow edges that lead to an unused vertex in the previous layer, and paths in the DFS tree must alternate between matched and unmatched edges.
, the DFS is continued from the next starting vertex.
running time for the DFS.
, which is the variant used in the pseudocode below.
.
The algorithm terminates when no more augmenting paths are found by the breadth first search step of one of the phases.
Analysis
.
edges in it. However, the symmetric difference of the eventual optimal matching and of the partial matching M additional phases before the algorithm terminates.
in the worst case.
In many instances, however, the time taken by the algorithm may be even faster than this worst-case analysis indicates. For instance, in the average case for sparse bipartite random graphs, (improving a previous result of ) showed that with high probability all non-optimal matchings have augmenting paths of logarithmic total time.
Comparison with other bipartite matching algorithms
For sparse graphs) a more recent algorithm by . Their algorithm is based on using a push-relabel maximum flow algorithm and then, when the matching created by this algorithm becomes close to optimum, switching to the Hopcroft–Karp method.
Several authors have performed experimental comparisons of bipartite matching algorithms. Their results in general tend to show that the Hopcroft–Karp method is not as good in practice as it is in theory: it is outperformed both by simpler breadth-first and depth-first strategies for finding augmenting paths, and by push-relabel techniques.
Non-bipartite graphs
phases. However, for non-bipartite graphs, the task of finding the augmenting paths within each phase is more difficult. Building on the work of several slower predecessors, showed how to implement a phase in linear time, resulting in a non-bipartite matching algorithm with the same time bound as the Hopcroft–Karp algorithm for bipartite graphs. The Micali–Vazirani technique is complex, and its authors did not provide full proofs of their results; subsequently, a "clear exposition" was published by and alternative methods were described by other authors. In 2012, Vazirani offered a new simplified proof of the Micali-Vazirani algorithm.
Pseudocode
/*
G = U ∪ V ∪ {NIL}
where U and V are the left and right sides of the bipartite graph and NIL is a special null vertex
*/
function BFS() is
for each u in U do
if Pair_U[u] = NIL then
Dist[u] := 0
Enqueue(Q, u)
else
Dist[u] := ∞
Dist[NIL] := ∞
while Empty(Q) = false do
u := Dequeue(Q)
if Dist[u] < Dist[NIL] then
for each v in Adj[u] do
if Dist[Pair_V[v]] = ∞ then
Dist[Pair_V[v]] := Dist[u] + 1
Enqueue(Q, Pair_V[v])
return Dist[NIL] ≠ ∞
function DFS(u) is
if u ≠ NIL then
for each v in Adj[u] do
if Dist[Pair_V[v]] = Dist[u] + 1 then
if DFS(Pair_V[v]) = true then
Pair_V[v] := u
Pair_U[u] := v
return true
Dist[u] := ∞
return false
return true
function Hopcroft–Karp is
for each u in U do
Pair_U[u] := NIL
for each v in V do
Pair_V[v] := NIL
matching := 0
while BFS() = true do
for each u in U do
if Pair_U[u] = NIL then
if DFS(u) = true then
matching := matching + 1
return matchingExplanation
Let the vertices of our graph be partitioned in U and V, and consider a partial matching, as indicated by the Pair_U and Pair_V tables that contain the one vertex to which each vertex of U and of V is matched, or NIL for unmatched vertices. The key idea is to add two dummy vertices on each side of the graph: uDummy connected to all unmatched vertices in U and vDummy connected to all unmatched vertices in V. Now, if we run a breadth-first search (BFS) from uDummy to vDummy then we can get the paths of minimal length that connect currently unmatched vertices in U to currently unmatched vertices in V. Note that, as the graph is bipartite, these paths always alternate between vertices in U and vertices in V, and we require in our BFS that when going from V to U, we always select a matched edge. If we reach an unmatched vertex of V, then we end at vDummy and the search for paths in the BFS terminate. To summarize, the BFS starts at unmatched vertices in U, goes to all their neighbors in V, if all are matched then it goes back to the vertices in U to which all these vertices are matched (and which were not visited before), then it goes to all the neighbors of these vertices, etc., until one of the vertices reached in V is unmatched.
Observe in particular that BFS marks the unmatched nodes of U with distance 0, then increments the distance every time it comes back to U. This guarantees that the paths considered in the BFS are of minimal length to connect unmatched vertices of U to unmatched vertices of V while always going back from V to U on edges that are currently part of the matching. In particular, the special NIL vertex, which corresponds to vDummy, then gets assigned a finite distance, so the BFS function returns true iff some path has been found. If no path has been found, then there are no augmenting paths left and the matching is maximal.
If BFS returns true, then we can go ahead and update the pairing for vertices on the minimal-length paths found from U to V: we do so using a depth-first search (DFS). Note that each vertex in V on such a path, except for the last one, is currently matched. So we can explore with the DFS, making sure that the paths that we follow correspond to the distances computed in the BFS. We update along every such path by removing from the matching all edges of the path that are currently in the matching, and adding to the matching all edges of the path that are currently not in the matching: as this is an augmenting path (the first and last edges of the path were not part of the matching, and the path alternated between matched and unmatched edges), then this increases the number of edges in the matching. This is same as replacing the current matching by the symmetric difference between the current matching and the entire path..
Note that the code ensures that all augmenting paths that we consider are vertex disjoint. Indeed, after doing the symmetric difference for a path, none of its vertices could be considered again in the DFS, just because the Dist[Pair_V[v]] will not be equal to Dist[u] + 1 (it would be exactly Dist[u]).
Also observe that the DFS does not visit the same vertex multiple times. This is thanks to the following lines:
Dist[u] = ∞
return falseWhen we were not able to find any shortest augmenting path from a vertex u, then the DFS marks vertex u by setting Dist[u] to infinity, so that these vertices are not visited again.
One last observation is that we actually don't need uDummy: its role is simply to put all unmatched vertices of U in the queue when we start the BFS. As for vDummy, it is denoted as NIL in the pseudocode above.
See also
Maximum cardinality matching, the problem solved by the algorithm, and its generalization to non-bipartite graphs
Assignment problem, a generalization of this problem on weighted graphs, solved e.g. by the Hungarian algorithm
Edmonds–Karp algorithm for finding maximum flow, a generalization of the Hopcroft–Karp algorithm
Notes
References
.
.
. As cited by .
. As cited by .
.
.
.
. Previously announced at the 12th Annual Symposium on Switching and Automata Theory, 1971.
. Previously announced at the Seminar on Combinatorial Mathematics (Moscow, 1971).
.
.
.
. As cited by .
.
.