P1035 棋盘覆盖 (二分图匹配、最大网络流)

本文介绍了如何解决棋盘覆盖问题,通过将二维棋盘转化为一维表示,并利用二分图最大匹配和最大网络流算法进行求解。在染色过程中,使用BFS避免DFS的栈溢出,并注意特定情况下正确染色的策略。文中提到了Hopcroft-Karp算法以及最大网络流法,这两种方法分别具有O((E + V) sqrt(V))和O(VE^2)的时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


描述

给出一张n*n(n<=100)的国际象棋棋盘,其中被删除了一些点,问可以使用多少1*2的多米诺骨牌进行掩盖。

输入格式

第一行为n,m(表示有m个删除的格子)
第二行到m+1行为x,y,分别表示删除格子所在的位置
x为第x行
y为第y列 

输出格式

一个数,即最大覆盖格数



二分图最大匹配


二维的棋盘可以转换为一维来表示,比如8*8棋盘上的点(6,5),转换为相应的一维id=44,点(x,y)转换公式为id=(x-1)*n+y-1 。


首先给用bfs或者dfs给棋盘染色,相邻的点染成不同的颜色,忽略被删除的点,dfs会爆栈,这里使用bfs。


特别注意例如以下情况,若bfs或dfs只以找到的第一个未删除的点为起点进行,则无法将如图“中间”的点进行正确染色导致匹配数不正确。


O O O O O O

O X X X X O

O X O O X O

O X O O X O

O X X X X O

O O O O O O

-------------------------------------------------------------------------------------------------------------------------------------------------------------


1.使用HopcroftKarp算法,遍历棋盘,给颜色不同且相邻的点添加一条边,所求就是最大匹配数。O((E + V) sqrt(

### 背景介绍 棋盘覆盖问题是经典的组合优化问题之一,通常可以通过二分图匹配来解决。具体来说,将棋盘上的每一个格子看作一个节点,并通过某种规则构建一张二分图。之后利用匈牙利算法或其他方法求解该二分图最大匹配。 --- ### 解决方案概述 #### 构建二分图 在一个 $n \times n$ 的棋盘中,可以按照如下方式定义二分图: - 将棋盘中的每一行视为左集合的一部分; - 将棋盘中的每一列视为右集合的一部分; - 如果某个位置 $(i, j)$ 可以被覆盖,则在对应的行 $i$ 和列 $j$ 之间建立一条无向边。 这样就得到了一个二分图模型[^1]。 #### 匈牙利算法的应用 为了找到棋盘上能够放置的最多不重叠覆盖物的数量,实际上就是寻找这个二分图最大匹配数。匈牙利算法是一种有效的解决方案,它基于增广路径的概念逐步扩展当前匹配直到无法继续改进为止[^2]。 以下是具体的实现过程: --- ### Python 实现代码 ```python from collections import defaultdict, deque def hungarian_algorithm(graph, n): """ 使用匈牙利算法计算二分图最大匹配。 :param graph: 邻接表表示的二分图 {left_node: [right_nodes]} :param n: 左侧顶点数量 :return: 最大匹配的结果列表 match[i]=j 表示左侧 i 连接到右侧 j """ def bfs(): queue = deque() for u in range(n): if not visited[u]: dist[u] = 0 queue.append(u) else: dist[u] = float('inf') while queue: u = queue.popleft() if dist[u] < float('inf'): for v in graph.get(u, []): w = match[v] if w != -1 and dist[w] == float('inf'): dist[w] = dist[u] + 1 queue.append(w) return dist[-1] != float('inf') def dfs(u): nonlocal visited for v in graph.get(u, []): w = match[v] if w == -1 or (dist[w] == dist[u]+1 and dfs(w)): match[v] = u visited[u] = True return True dist[u] = float('inf') return False m = max(max(vv) for vv in graph.values()) + 1 if graph else 0 match = [-1]*m result = [] visited = [False]*n dist = [float('inf')]*n for _ in range(m): if bfs(): visited = [False]*n for u in range(n): if not visited[u] and dfs(u): pass else: break for key, value in enumerate(match): if value != -1: result.append((value, key)) return result # 示例输入:构造一个简单的棋盘并转化为二分图 if __name__ == "__main__": # 假设有一个 4x4 棋盘,部分位置不可用 board_size = 4 unavailable_positions = [(1, 1), (2, 3)] # 不可用的位置坐标 # 创建邻接表形式的二分图 bipartite_graph = defaultdict(list) for row in range(board_size): for col in range(board_size): if (row, col) not in unavailable_positions: bipartite_graph[row].append(col) # 执行匈牙利算法得到最大匹配 matching_result = hungarian_algorithm(bipartite_graph, board_size) print("最大匹配结果:", matching_result) ``` 上述程序实现了如何通过匈牙利算法解决棋盘覆盖问题的核心逻辑。 --- ### 结果分析 运行以上代码后会输出棋盘上可放置的最大非冲突覆盖数目及其对应的具体位置关系。这正是我们期望获得的信息——即满足条件下的最优布局策略。 --- ### 注意事项 尽管此方法适用于大多数标准情况,但在实际应用过程中还需注意边界处理以及特殊情形(比如完全空白或者全满状态)。此外,在大规模数据集下性能可能成为瓶颈,因此需考虑更高效的替代方案如 Hopcroft-Karp 算法等。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值