from queue import Queue
class Bipartite:
# 传入图中的边信息,所有边起点属于二分图part1, 所有边终点属于二分图part2, 输入数据自行保证没有重边
def __init__(self, edges):
self.edges = edges
self.__match_result = None
# 判断是否是二分图
def __isBipartite(self):
link = {}
node_color = {} # 节点的颜色
for a, b in self.edges:
if a not in link:
link[a] = []
if b not in link:
link[b] = []
link[a].append(b)
link[b].append(a)
node_color[a] = None
node_color[b] = None
def __dfs(cur, color) -> bool:
node_color[cur] = color
for next in link[cur]:
if node_color[next] == color:
return False
if node_color[next] is None:
if not __dfs(next, 1-color):
return False
return True
for node, color in node_color.items():
if color is None:
if not __dfs(node, 1):
return False
return True
# 是否是完全匹配
def isPerfectMatching(self):
if self.__match_result is None:
self.getMaxMatchNum()
if self.__match_result is None:
return False
all_nodes = set()
for a, b in self.edges:
all_nodes.add(a)
all_nodes.add(b)
# 最大匹配树乘以2就是匹配的节点数,匹配节点数和总结点数相同即为完全匹配
return self.__match_result[0] * 2 == len(all_nodes)
# 获取二分图最大匹配数量, 如果无法进行二分图匹配,返回None, 正常情况返回 (最大匹配数,最大匹配边列表)
def getMaxMatchNum(self):
if not self.__isBipartite():
return None
# 构建邻接表
link = {}
for a, b in self.edges:
if a not in link:
link[a] = []
link[a].append(b)
part1_nodes = set([a for a, _ in self.edges]) # 所有属于part1中的节点
part2_node2matched = {b: None for _, b in self.edges} # 记录part2中节点和part1中哪个节点匹配
for start_node in part1_nodes:
que = Queue()
pre = {start_node: None}
visited = set()
visited.add(start_node)
que.put(start_node)
end_node = None
while not que.empty():
cur = que.get()
if cur in link:
for next in link[cur]:
if next not in visited:
visited.add(next)
pre[next] = cur
if part2_node2matched[next] is None:
# 找到非匹配点,也就是找到了增广路径
end_node = next
break
else:
pre[part2_node2matched[next]] = next
que.put(part2_node2matched[next])
path = []
if end_node:
while pre[end_node] is not None:
path.append((pre[end_node], end_node))
end_node = pre[end_node]
# 根据增广路径更新图的状态
flag = True
for a, b in reversed(path):
if flag:
# 非匹配边转换为匹配边
part2_node2matched[b] = a
flag = not flag
selected_edges = []
for node, matched_node in part2_node2matched.items():
if matched_node is not None:
selected_edges.append((matched_node, node))
self.__match_result = len(selected_edges), selected_edges
return self.__match_result
# 获取二分图最大匹配结果中的匹配边, 没有合法的二分图匹配方式返回None
def getMaxMatchEdges(self):
if self.__match_result is None:
self.getMaxMatchNum()
if self.__match_result is None:
return None
return [(a, b) for a, b in self.__match_result[1]]
n1, n2, m = map(int, input().split())
edges = set()
for i in range(m):
a, b = map(int, input().split())
edges.add((a, b))
edges = [(a, b+1000000) for a, b in edges]
algo = Bipartite(edges)
print(algo.getMaxMatchNum()[0])