📅  最后修改于: 2023-12-03 15:41:33.707000             🧑  作者: Mango
给定一个二维网格,求覆盖该网格的所有块所需的最小点数。
一个点可以覆盖网格中的一行或一列,或与一行或一列相交的格子。
该问题可以转化为一个二分图的最小顶点覆盖问题。
将网格中的每行和每列看作一个顶点,如果一个点覆盖了某一行或某一列,则在对应的顶点之间连一条边。
则覆盖所有块所需的最小点数等价于在该二分图中选出尽量少的顶点,使得每条边都至少有一个端点被选中。
最小顶点覆盖问题可以通过求最大匹配问题来解决。
from typing import List
def min_vertex_cover(grid: List[List[int]]) -> int:
n, m = len(grid), len(grid[0])
# 构建二分图
graph = [[] for _ in range(n + m)]
for i in range(n):
for j in range(m):
if grid[i][j] == 1:
graph[i].append(n + j)
graph[n + j].append(i)
# 求最大匹配
matching = [-1] * (n + m)
def dfs(u: int) -> bool:
for v in graph[u]:
if not used[v]:
used[v] = True
if matching[v] == -1 or dfs(matching[v]):
matching[u] = v
matching[v] = u
return True
return False
for i in range(n):
used = [False] * (n + m)
dfs(i)
# 计算顶点覆盖数
cover = set()
for i in range(n):
if matching[i] == -1:
cover.add(i)
for j in range(n, n + m):
if matching[j] != -1:
cover.add(matching[j])
return len(cover)
代码解释:
0
到 n-1
和 n
到 n+m-1
;used
数组为 DFS 时用来记录某个顶点是否已被访问过;set()
来去重。