mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-12-04 02:11:08 +00:00
Resolved Pre commit errors
This commit is contained in:
parent
991a37e9ff
commit
11a3c242ca
|
@ -2,6 +2,8 @@ from collections import deque
|
||||||
|
|
||||||
|
|
||||||
class BlossomAuxData:
|
class BlossomAuxData:
|
||||||
|
"""Class to hold auxiliary data during the blossom algorithm's execution."""
|
||||||
|
|
||||||
def __init__(self, queue: deque, parent: list[int], base: list[int],
|
def __init__(self, queue: deque, parent: list[int], base: list[int],
|
||||||
in_blossom: list[bool], match: list[int], in_queue: list[bool]):
|
in_blossom: list[bool], match: list[int], in_queue: list[bool]):
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
|
@ -11,18 +13,33 @@ class BlossomAuxData:
|
||||||
self.match = match
|
self.match = match
|
||||||
self.in_queue = in_queue
|
self.in_queue = in_queue
|
||||||
|
|
||||||
|
|
||||||
class BlossomData:
|
class BlossomData:
|
||||||
|
"""Class to encapsulate data related to a blossom in the graph."""
|
||||||
|
|
||||||
def __init__(self, aux_data: BlossomAuxData, u: int, v: int, lca: int):
|
def __init__(self, aux_data: BlossomAuxData, u: int, v: int, lca: int):
|
||||||
self.aux_data = aux_data
|
self.aux_data = aux_data
|
||||||
self.u = u
|
self.u = u
|
||||||
self.v = v
|
self.v = v
|
||||||
self.lca = lca
|
self.lca = lca
|
||||||
|
|
||||||
|
|
||||||
class EdmondsBlossomAlgorithm:
|
class EdmondsBlossomAlgorithm:
|
||||||
UNMATCHED = -1 # Constant to represent unmatched vertices
|
UNMATCHED = -1 # Constant to represent unmatched vertices
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def maximum_matching(edges: list[list[int]], vertex_count: int) -> list[list[int]]:
|
def maximum_matching(edges: list[list[int]], vertex_count: int) -> list[list[int]]:
|
||||||
|
"""
|
||||||
|
Finds the maximum matching in a graph using the Edmonds Blossom Algorithm.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
edges: A list of edges represented as pairs of vertices.
|
||||||
|
vertex_count: The total number of vertices in the graph.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
A list of matched pairs in the form of a list of lists.
|
||||||
|
"""
|
||||||
|
# Create an adjacency list for the graph
|
||||||
graph = [[] for _ in range(vertex_count)]
|
graph = [[] for _ in range(vertex_count)]
|
||||||
|
|
||||||
# Populate the graph with the edges
|
# Populate the graph with the edges
|
||||||
|
@ -35,12 +52,12 @@ class EdmondsBlossomAlgorithm:
|
||||||
match = [EdmondsBlossomAlgorithm.UNMATCHED] * vertex_count
|
match = [EdmondsBlossomAlgorithm.UNMATCHED] * vertex_count
|
||||||
parent = [EdmondsBlossomAlgorithm.UNMATCHED] * vertex_count
|
parent = [EdmondsBlossomAlgorithm.UNMATCHED] * vertex_count
|
||||||
base = list(range(vertex_count)) # Each vertex is its own base initially
|
base = list(range(vertex_count)) # Each vertex is its own base initially
|
||||||
# Indicates if a vertex is part of a blossom
|
|
||||||
in_blossom = [False] * vertex_count
|
in_blossom = [False] * vertex_count
|
||||||
in_queue = [False] * vertex_count # Tracks vertices in the BFS queue
|
in_queue = [False] * vertex_count # Tracks vertices in the BFS queue
|
||||||
|
|
||||||
# Main logic for finding maximum matching
|
# Main logic for finding maximum matching
|
||||||
for u in range(vertex_count):
|
for u in range(vertex_count):
|
||||||
|
# Only consider unmatched vertices
|
||||||
if match[u] == EdmondsBlossomAlgorithm.UNMATCHED:
|
if match[u] == EdmondsBlossomAlgorithm.UNMATCHED:
|
||||||
# BFS initialization
|
# BFS initialization
|
||||||
parent = [EdmondsBlossomAlgorithm.UNMATCHED] * vertex_count
|
parent = [EdmondsBlossomAlgorithm.UNMATCHED] * vertex_count
|
||||||
|
@ -48,59 +65,58 @@ class EdmondsBlossomAlgorithm:
|
||||||
in_blossom = [False] * vertex_count
|
in_blossom = [False] * vertex_count
|
||||||
in_queue = [False] * vertex_count
|
in_queue = [False] * vertex_count
|
||||||
|
|
||||||
queue = deque([u])
|
queue = deque([u]) # Start BFS from the unmatched vertex
|
||||||
in_queue[u] = True
|
in_queue[u] = True
|
||||||
|
|
||||||
augmenting_path_found = False
|
augmenting_path_found = False
|
||||||
|
|
||||||
# BFS to find augmenting paths
|
# BFS to find augmenting paths
|
||||||
while queue and not augmenting_path_found:
|
while queue and not augmenting_path_found:
|
||||||
current = queue.popleft()
|
current = queue.popleft() # Get the current vertex
|
||||||
for y in graph[current]:
|
for y in graph[current]: # Explore adjacent vertices
|
||||||
|
# Skip if we're looking at the current match
|
||||||
if match[current] == y:
|
if match[current] == y:
|
||||||
# Skip if we are
|
|
||||||
# looking at the same edge
|
|
||||||
# as the current match
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if base[current] == base[y]:
|
if base[current] == base[y]: # Avoid self-loops
|
||||||
continue # Avoid self-loops
|
continue
|
||||||
|
|
||||||
if parent[y] == EdmondsBlossomAlgorithm.UNMATCHED:
|
if parent[y] == EdmondsBlossomAlgorithm.UNMATCHED:
|
||||||
# Case 1: y is unmatched, we've found an augmenting path
|
# Case 1: y is unmatched; we've found an augmenting path
|
||||||
if match[y] == EdmondsBlossomAlgorithm.UNMATCHED:
|
if match[y] == EdmondsBlossomAlgorithm.UNMATCHED:
|
||||||
parent[y] = current
|
parent[y] = current # Update the parent
|
||||||
augmenting_path_found = True
|
augmenting_path_found = True
|
||||||
# Augment along this path
|
# Augment along this path
|
||||||
(EdmondsBlossomAlgorithm
|
EdmondsBlossomAlgorithm.update_matching(match,
|
||||||
.update_matching(match, parent, y))
|
parent,
|
||||||
|
y)
|
||||||
break
|
break
|
||||||
|
|
||||||
# Case 2: y is matched, add y's match to the queue
|
# Case 2: y is matched; add y's match to the queue
|
||||||
z = match[y]
|
z = match[y]
|
||||||
parent[y] = current
|
parent[y] = current
|
||||||
parent[z] = y
|
parent[z] = y
|
||||||
if not in_queue[z]:
|
if not in_queue[z]: # If z is not already in the queue
|
||||||
queue.append(z)
|
queue.append(z)
|
||||||
in_queue[z] = True
|
in_queue[z] = True
|
||||||
else:
|
else:
|
||||||
# Case 3: Both current and y have a parent;
|
# Case 3: Both current and y have a parent;
|
||||||
# check for a cycle/blossom
|
# check for a cycle/blossom
|
||||||
base_u = EdmondsBlossomAlgorithm.find_base(base,
|
base_u = EdmondsBlossomAlgorithm.find_base(base,
|
||||||
parent, current, y)
|
parent,
|
||||||
|
current,
|
||||||
|
y)
|
||||||
if base_u != EdmondsBlossomAlgorithm.UNMATCHED:
|
if base_u != EdmondsBlossomAlgorithm.UNMATCHED:
|
||||||
EdmondsBlossomAlgorithm.contract_blossom(BlossomData(
|
EdmondsBlossomAlgorithm.contract_blossom(BlossomData(
|
||||||
BlossomAuxData(queue,
|
BlossomAuxData(queue, parent,
|
||||||
parent,
|
base, in_blossom,
|
||||||
base,
|
match, in_queue),
|
||||||
in_blossom,
|
|
||||||
match,
|
|
||||||
in_queue),
|
|
||||||
current, y, base_u))
|
current, y, base_u))
|
||||||
|
|
||||||
# Create result list of matched pairs
|
# Create result list of matched pairs
|
||||||
matching_result = []
|
matching_result = []
|
||||||
for v in range(vertex_count):
|
for v in range(vertex_count):
|
||||||
|
# Ensure pairs are unique
|
||||||
if match[v] != EdmondsBlossomAlgorithm.UNMATCHED and v < match[v]:
|
if match[v] != EdmondsBlossomAlgorithm.UNMATCHED and v < match[v]:
|
||||||
matching_result.append([v, match[v]])
|
matching_result.append([v, match[v]])
|
||||||
|
|
||||||
|
@ -108,22 +124,42 @@ class EdmondsBlossomAlgorithm:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def update_matching(match: list[int], parent: list[int], u: int):
|
def update_matching(match: list[int], parent: list[int], u: int):
|
||||||
|
"""
|
||||||
|
Updates the matching based on the augmenting path found.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
match: The current match list.
|
||||||
|
parent: The parent list from BFS traversal.
|
||||||
|
u: The vertex where the augmenting path ends.
|
||||||
|
"""
|
||||||
while u != EdmondsBlossomAlgorithm.UNMATCHED:
|
while u != EdmondsBlossomAlgorithm.UNMATCHED:
|
||||||
v = parent[u]
|
v = parent[u] # Get the parent vertex
|
||||||
next_match = match[v]
|
next_match = match[v] # Store the next match
|
||||||
match[v] = u
|
match[v] = u # Update match for v
|
||||||
match[u] = v
|
match[u] = v # Update match for u
|
||||||
u = next_match
|
u = next_match # Move to the next vertex
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def find_base(base: list[int], parent: list[int], u: int, v: int) -> int:
|
def find_base(base: list[int], parent: list[int], u: int, v: int) -> int:
|
||||||
|
"""
|
||||||
|
Finds the base of the blossom.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
base: The base array for each vertex.
|
||||||
|
parent: The parent array from BFS.
|
||||||
|
u: One endpoint of the blossom.
|
||||||
|
v: The other endpoint of the blossom.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The lowest common ancestor of u and v in the blossom.
|
||||||
|
"""
|
||||||
visited = [False] * len(base)
|
visited = [False] * len(base)
|
||||||
|
|
||||||
# Mark ancestors of u
|
# Mark ancestors of u
|
||||||
current_u = u
|
current_u = u
|
||||||
while True:
|
while True:
|
||||||
current_u = base[current_u]
|
current_u = base[current_u]
|
||||||
visited[current_u] = True
|
visited[current_u] = True # Mark this base as visited
|
||||||
if parent[current_u] == EdmondsBlossomAlgorithm.UNMATCHED:
|
if parent[current_u] == EdmondsBlossomAlgorithm.UNMATCHED:
|
||||||
break
|
break
|
||||||
current_u = parent[current_u]
|
current_u = parent[current_u]
|
||||||
|
@ -132,16 +168,24 @@ class EdmondsBlossomAlgorithm:
|
||||||
current_v = v
|
current_v = v
|
||||||
while True:
|
while True:
|
||||||
current_v = base[current_v]
|
current_v = base[current_v]
|
||||||
if visited[current_v]:
|
if visited[current_v]: # Check if we've already visited this base
|
||||||
return current_v
|
return current_v
|
||||||
current_v = parent[current_v]
|
current_v = parent[current_v]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def contract_blossom(blossom_data: BlossomData):
|
def contract_blossom(blossom_data: BlossomData):
|
||||||
|
"""
|
||||||
|
Contracts a blossom found during the matching process.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
blossom_data: The data related to the blossom to be contracted.
|
||||||
|
"""
|
||||||
|
# Mark vertices in the blossom
|
||||||
for x in range(blossom_data.u,
|
for x in range(blossom_data.u,
|
||||||
blossom_data.aux_data.base[blossom_data.u] != blossom_data.lca):
|
blossom_data.aux_data.base[blossom_data.u] != blossom_data.lca):
|
||||||
base_x = blossom_data.aux_data.base[x]
|
base_x = blossom_data.aux_data.base[x]
|
||||||
match_base_x = blossom_data.aux_data.base[blossom_data.aux_data.match[x]]
|
match_base_x = blossom_data.aux_data.base[blossom_data.aux_data.match[x]]
|
||||||
|
# Mark the base as in a blossom
|
||||||
blossom_data.aux_data.in_blossom[base_x] = True
|
blossom_data.aux_data.in_blossom[base_x] = True
|
||||||
blossom_data.aux_data.in_blossom[match_base_x] = True
|
blossom_data.aux_data.in_blossom[match_base_x] = True
|
||||||
|
|
||||||
|
@ -149,6 +193,7 @@ class EdmondsBlossomAlgorithm:
|
||||||
blossom_data.aux_data.base[blossom_data.v] != blossom_data.lca):
|
blossom_data.aux_data.base[blossom_data.v] != blossom_data.lca):
|
||||||
base_x = blossom_data.aux_data.base[x]
|
base_x = blossom_data.aux_data.base[x]
|
||||||
match_base_x = blossom_data.aux_data.base[blossom_data.aux_data.match[x]]
|
match_base_x = blossom_data.aux_data.base[blossom_data.aux_data.match[x]]
|
||||||
|
# Mark the base as in a blossom
|
||||||
blossom_data.aux_data.in_blossom[base_x] = True
|
blossom_data.aux_data.in_blossom[base_x] = True
|
||||||
blossom_data.aux_data.in_blossom[match_base_x] = True
|
blossom_data.aux_data.in_blossom[match_base_x] = True
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user