Kuhn Algorithm for finding the maximum matching in bipartite graphs
Learn Kuhn Algorithm for finding the maximum matching in bipartite graphs step by step with clear examples and exercises.
Why This Matters
Maximum matchings in graphs have a wide range of applications, from computer science to economics and social networks. Understanding Kuhn's algorithm for finding maximum matchings in bipartite graphs is essential for competitive programming contests, as well as solving real-world problems that can be modeled as graph matching problems. Furthermore, understanding the principles of augmenting paths is crucial in various graph algorithms.
Prerequisites
To follow this lesson, you should have a good understanding of:
- Basic Python programming concepts (variables, functions, loops, recursion)
- Graph data structures and traversal algorithms (Breadth First Search, Depth First Search)
- Familiarity with graph theory concepts such as vertices, edges, adjacency lists, and bipartite graphs
Core Concept
A bipartite graph is a graph where the vertices can be divided into two disjoint sets such that every edge connects a vertex in one set to a vertex in the other. In this lesson, we will focus on finding the maximum matching in a given bipartite graph using Kuhn's algorithm.
A matching in a graph is a set of edges no two of which share a common vertex (except at their ends). A maximum matching is a matching with the maximum possible number of edges.
Kuhn's algorithm works by finding augmenting paths, i.e., paths that start and end on unmatched vertices and alternate between matched and unmatched edges. The idea is to find an augmenting path and then update the matching to include the new edge in the path while removing one of the old edges.
Augmenting Paths
An augmenting path in a graph with a given matching M is a path that starts at an unmatched vertex, alternates between matched and unmatched edges, and ends at another unmatched vertex. The length of an augmenting path is the number of edges it contains.
Augmenting Path Algorithm
To find an augmenting path in a graph with a given matching M, we perform a Depth First Search (DFS) starting from an unmatched vertex. If we encounter a matched vertex, we backtrack and continue our search from the other endpoint of the matched edge. If we reach another unmatched vertex, we have found an augmenting path.
Kuhn's Algorithm
Kuhn's algorithm iteratively finds augmenting paths in the graph until no more augmenting paths can be found. At each iteration, it updates the matching by adding the new edge from the augmenting path and removing one of the old edges. The process continues until a maximum matching is reached or no more augmenting paths can be found.
Worked Example
Let's consider the following bipartite graph:
A B C D E F G H I J
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10
11| | | | | | |
12| | | | | | |
13| | | | | | |
14| | | | | | |
15| | | | | | |
Initially, the matching M is empty. We start by finding an augmenting path and updating the matching:
- DFS from vertex D:
- Visit D (unmatched)
- Visit matched vertex 4 (since there's no edge between D and any other unmatched vertices)
- Backtrack to 4
- Visit unmatched vertex E (not connected to 4, so backtrack)
- Visit matched vertex 5 (since there's no edge between E and any other unmatched vertices)
- Backtrack to 5
- Visit unmatched vertex C (connected via edge (C,5), so add this edge to the path)
- Visit matched vertex 3 (since there's no edge between C and any other unmatched vertices)
- Backtrack to 3
- Visit unmatched vertex A (not connected to 3, so backtrack)
- Visit matched vertex 2 (since there's no edge between A and any other unmatched vertices)
- Backtrack to 2
- Visit unmatched vertex B (connected via edge (B,2), so add this edge to the path)
We have found an augmenting path: D - 4 - E - 5 - C - 3 - B - 2. To update the matching M, we add the new edge (C, 3) and remove one of the old edges (either (D, 4) or (B, 2)). Let's choose to remove (B, 2). The updated matching M' now consists of the edges: {(C, 3), (E, 5)}.
We continue this process until no more augmenting paths can be found. In this case, we find that the maximum matching consists of the edges: {(C, 3), (E, 5), (A, 1)} and there are no more augmenting paths to be found.
def is_matched(graph, matching):
for vertex in graph:
if len(vertex) > len(matching[vertex]) and vertex not in matching:
return False
return True
def find_augmenting_path(graph, matching):
def dfs(current, path, used):
if current in matching:
other = matching[current]
del path[-1]
if other not in used and dfs(other, path + [other], used | {other}):
return True
elif len(current) > len(matching[current]) and current not in used:
path.append(current)
used.add(current)
for neighbor in graph[current]:
if neighbor not in used and dfs(neighbor, path, used | {current}):
return True
path.pop()
used.remove(current)
return False
for vertex in graph:
if len(vertex) > len(matching[vertex]) and vertex not in matching:
if dfs(vertex, [vertex], set()):
return path
return None
def kuhn_algorithm(graph):
matching = {}
while find_augmenting_path(graph, matching):
path = find_augmenting_path(graph, matching)
new_edge = path[-1]
old_edge = matching[path[0]] if path[0] in matching else None
matching.update({new_edge: path[0], path[0]: new_edge})
if old_edge:
vertex, matched_vertex = old_edge
del matching[vertex][matched_vertex]
return matching
Common Mistakes
- Not checking for cycles during DFS: If a cycle is encountered during DFS, it means we have an odd cycle, which contradicts the existence of a maximum matching. In this case, we should terminate the algorithm and return the current matching as the maximum one.
- Incorrect edge selection when updating the matching: When updating the matching by adding a new edge and removing an old one, it is important to choose the correct old edge to remove. If we choose incorrectly, we may not find the maximum matching.
Common Mistakes (Cont'd)
- Not handling vertices with degree zero: Vertices with degree zero cannot be part of an augmenting path and are therefore ignored during the search for augmenting paths. However, if all vertices in one set have degree zero, the graph is said to be empty and no matching exists. In this case, we should return an empty dictionary instead of attempting to find a maximum matching.
Practice Questions
- Implement Kuhn's algorithm for finding the maximum matching in a given bipartite graph using Python.
- Given a bipartite graph and an initial matching, write a function to check if the given matching is maximum or not using Kuhn's algorithm.
- Consider the following bipartite graph:
A B C D E F G H I J
1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10
11| | | | | | |
12| | | | | | |
13| | | | | | |
14| | | | | | |
15| | | | | | |
Find the maximum matching using Kuhn's algorithm.
FAQ
Q: What is the time complexity of Kuhn's algorithm?
A: The time complexity of Kuhn's algorithm is O(V^3) in the worst case, where V is the number of vertices in the graph. In practice, however, it often performs much better due to early termination when a maximum matching is found or no more augmenting paths can be found.
Q: Can Kuhn's algorithm be used for non-bipartite graphs?
A: No, Kuhn's algorithm is specifically designed for finding the maximum matching in bipartite graphs. For non-bipartite graphs, other algorithms such as Hungarian Algorithm or Edmonds' Blossom Algorithm can be used.
Q: How does Kuhn's algorithm handle unmatched vertices with degree zero?
A: Vertices with degree zero cannot be part of an augmenting path and are therefore ignored during the search for augmenting paths. In practice, such vertices do not affect the maximum matching since they can never be matched. However, if all vertices in one set have degree zero, the graph is said to be empty and no matching exists. In this case, we should return an empty dictionary instead of attempting to find a maximum matching.