Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 20e53ed

Browse files
committed
更新「二分图最大匹配」相关内容
1 parent 79c30ef commit 20e53ed

File tree

1 file changed

+277
-0
lines changed

1 file changed

+277
-0
lines changed
Lines changed: 277 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,277 @@
1+
## 1. 二分图最大匹配简介
2+
3+
> **二分图最大匹配(Maximum Bipartite Matching)**:图论中的一个重要问题。在二分图中,我们需要找到最大的匹配数,即最多可以有多少对顶点之间形成匹配。
4+
5+
- **二分图**:图中的顶点可以被分成两个独立的集合,使得每条边的两个端点分别属于这两个集合。
6+
- **匹配**:一组边的集合,其中任意两条边都没有共同的顶点。
7+
- **最大匹配**:包含边数最多的匹配。
8+
9+
### 1.1 应用场景
10+
11+
二分图最大匹配在实际应用中有广泛的应用:
12+
13+
1. **任务分配**:将任务分配给工人,每个工人只能完成一个任务
14+
2. **婚姻匹配**:将男生和女生进行配对
15+
3. **网络流问题**:可以转化为最大流问题求解
16+
4. **资源分配**:将资源分配给需求方
17+
5. **学生选课**:将学生与课程进行匹配
18+
6. **网络路由**:将数据包与可用路径进行匹配
19+
20+
### 1.2 优化方法
21+
22+
1. **使用邻接表**:对于稀疏图,使用邻接表可以显著减少空间复杂度
23+
2. **双向搜索**:同时从左右两侧进行搜索,可以减少搜索次数
24+
3. **预处理**:对图进行预处理,去除不可能形成匹配的边
25+
4. **贪心匹配**:先进行贪心匹配,减少后续搜索的复杂度
26+
5. **并行处理**:对于大规模图,可以使用并行算法提高效率
27+
28+
## 2. 匈牙利算法
29+
30+
### 2.1 匈牙利算法基本思想
31+
32+
匈牙利算法(Hungarian Algorithm)是求解二分图最大匹配的经典算法。其基本思想是:
33+
34+
1. 从左侧集合中任选一个未匹配的点开始
35+
2. 尝试寻找增广路径
36+
3. 如果找到增广路径,则更新匹配
37+
4. 重复以上步骤直到无法找到增广路径
38+
39+
### 2.2 匈牙利算法实现代码
40+
41+
```python
42+
def max_bipartite_matching(graph, left_size, right_size):
43+
# 初始化匹配数组
44+
match_right = [-1] * right_size
45+
result = 0
46+
47+
# 对左侧每个顶点尝试匹配
48+
for left in range(left_size):
49+
# 记录右侧顶点是否被访问过
50+
visited = [False] * right_size
51+
52+
# 如果找到增广路径,则匹配数加1
53+
if find_augmenting_path(graph, left, visited, match_right):
54+
result += 1
55+
56+
return result
57+
58+
def find_augmenting_path(graph, left, visited, match_right):
59+
# 遍历右侧所有顶点
60+
for right in range(len(graph[left])):
61+
# 如果存在边且右侧顶点未被访问
62+
if graph[left][right] and not visited[right]:
63+
visited[right] = True
64+
65+
# 如果右侧顶点未匹配,或者可以找到新的匹配
66+
if match_right[right] == -1 or find_augmenting_path(graph, match_right[right], visited, match_right):
67+
match_right[right] = left
68+
return True
69+
70+
return False
71+
```
72+
73+
### 2.3 匈牙利算法时间复杂度
74+
75+
- 匈牙利算法的时间复杂度为 O(VE),其中 V 是顶点数,E 是边数
76+
- 使用邻接矩阵存储图时,空间复杂度为 O(V2)
77+
- 使用邻接表存储图时,空间复杂度为 O(V + E)
78+
79+
80+
## 3. Hopcroft-Karp 算法
81+
82+
### 3.1 Hopcroft-Karp 算法基本思想
83+
84+
Hopcroft-Karp 算法是求解二分图最大匹配的一个更高效的算法,时间复杂度为 O(√VE)。其基本思想是:
85+
86+
1. 同时寻找多条不相交的增广路径
87+
2. 使用 BFS 分层,然后使用 DFS 寻找增广路径
88+
3. 每次迭代可以找到多条增广路径
89+
90+
91+
### 3.2 Hopcroft-Karp 算法实现代码
92+
93+
```python
94+
from collections import deque
95+
96+
def hopcroft_karp(graph, left_size, right_size):
97+
# 初始化匹配数组
98+
match_left = [-1] * left_size
99+
match_right = [-1] * right_size
100+
result = 0
101+
102+
while True:
103+
# 使用 BFS 寻找增广路径
104+
dist = [-1] * left_size
105+
queue = deque()
106+
107+
# 将未匹配的左侧顶点加入队列
108+
for i in range(left_size):
109+
if match_left[i] == -1:
110+
dist[i] = 0
111+
queue.append(i)
112+
113+
# BFS 分层
114+
while queue:
115+
left = queue.popleft()
116+
for right in graph[left]:
117+
if match_right[right] == -1:
118+
# 找到增广路径
119+
break
120+
if dist[match_right[right]] == -1:
121+
dist[match_right[right]] = dist[left] + 1
122+
queue.append(match_right[right])
123+
124+
# 使用 DFS 寻找增广路径
125+
def dfs(left):
126+
for right in graph[left]:
127+
if match_right[right] == -1 or \
128+
(dist[match_right[right]] == dist[left] + 1 and \
129+
dfs(match_right[right])):
130+
match_left[left] = right
131+
match_right[right] = left
132+
return True
133+
return False
134+
135+
# 尝试为每个未匹配的左侧顶点寻找增广路径
136+
found = False
137+
for i in range(left_size):
138+
if match_left[i] == -1 and dfs(i):
139+
found = True
140+
result += 1
141+
142+
if not found:
143+
break
144+
145+
return result
146+
```
147+
148+
### 3.3 Hopcroft-Karp 算法复杂度
149+
150+
- **时间复杂度**:O(√VE),其中 V 是顶点数,E 是边数
151+
- **空间复杂度**:O(V + E)
152+
- **优点**:
153+
1. 比匈牙利算法更高效
154+
2. 适合处理大规模图
155+
3. 可以并行化实现
156+
- **缺点**:
157+
1. 实现相对复杂
158+
2. 常数因子较大
159+
3. 对于小规模图可能不如匈牙利算法
160+
161+
### 3.4 Hopcroft-Karp 算法优化
162+
163+
1. **双向 BFS**:同时从左右两侧进行 BFS,减少搜索空间
164+
2. **动态分层**:根据当前匹配状态动态调整分层策略
165+
3. **预处理**:使用贪心算法进行初始匹配
166+
4. **并行化**:利用多线程或分布式计算提高效率
167+
168+
## 4. 网络流算法
169+
170+
### 4.1 网络流算法实现步骤
171+
172+
二分图最大匹配问题可以转化为最大流问题来求解。具体步骤如下:
173+
174+
1. 添加源点和汇点
175+
2. 将二分图转化为网络流图
176+
3. 使用最大流算法求解
177+
178+
### 4.2 网络流算法实现代码
179+
180+
```python
181+
from collections import defaultdict
182+
183+
def max_flow_bipartite_matching(graph, left_size, right_size):
184+
# 构建网络流图
185+
flow_graph = defaultdict(dict)
186+
source = left_size + right_size
187+
sink = source + 1
188+
189+
# 添加源点到左侧顶点的边
190+
for i in range(left_size):
191+
flow_graph[source][i] = 1
192+
flow_graph[i][source] = 0
193+
194+
# 添加右侧顶点到汇点的边
195+
for i in range(right_size):
196+
flow_graph[left_size + i][sink] = 1
197+
flow_graph[sink][left_size + i] = 0
198+
199+
# 添加二分图中的边
200+
for i in range(left_size):
201+
for j in graph[i]:
202+
flow_graph[i][left_size + j] = 1
203+
flow_graph[left_size + j][i] = 0
204+
205+
# 使用 Ford-Fulkerson 算法求解最大流
206+
def bfs():
207+
parent = [-1] * (sink + 1)
208+
queue = deque([source])
209+
parent[source] = -2
210+
211+
while queue:
212+
u = queue.popleft()
213+
for v, capacity in flow_graph[u].items():
214+
if parent[v] == -1 and capacity > 0:
215+
parent[v] = u
216+
if v == sink:
217+
return parent
218+
queue.append(v)
219+
return None
220+
221+
def ford_fulkerson():
222+
max_flow = 0
223+
while True:
224+
parent = bfs()
225+
if not parent:
226+
break
227+
228+
# 找到增广路径上的最小容量
229+
v = sink
230+
min_capacity = float('inf')
231+
while v != source:
232+
u = parent[v]
233+
min_capacity = min(min_capacity, flow_graph[u][v])
234+
v = u
235+
236+
# 更新流量
237+
v = sink
238+
while v != source:
239+
u = parent[v]
240+
flow_graph[u][v] -= min_capacity
241+
flow_graph[v][u] += min_capacity
242+
v = u
243+
244+
max_flow += min_capacity
245+
246+
return max_flow
247+
248+
return ford_fulkerson()
249+
```
250+
251+
### 4.3 网络流算法复杂度
252+
253+
- **时间复杂度**:
254+
1. Ford-Fulkerson 算法:O(VE2)
255+
2. Dinic 算法:O(V2E)
256+
3. ISAP 算法:O(V2E)
257+
- **空间复杂度**:O(V + E)
258+
259+
## 5. 算法复杂度分析
260+
261+
1. **匈牙利算法**
262+
- 时间复杂度:O(VE)
263+
- 优点:实现简单,容易理解
264+
- 缺点:对于大规模图效率较低
265+
- 适用场景:小规模图,需要快速实现
266+
267+
2. **Hopcroft-Karp 算法**
268+
- 时间复杂度:O(√VE)
269+
- 优点:效率更高,适合大规模图
270+
- 缺点:实现相对复杂
271+
- 适用场景:大规模图,需要高效算法
272+
273+
3. **网络流算法**
274+
- 时间复杂度:O(VE2) 或 O(V2E)
275+
- 优点:可以处理更复杂的问题,如带权匹配
276+
- 缺点:实现复杂,常数较大
277+
- 适用场景:带权匹配,复杂约束条件

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /