原题链接:棋盘覆盖
解题思路:
问题转化:
将棋盘覆盖转化为二分图匹配多米诺骨牌需覆盖相邻两格,且必然是一个黑格和一个白格(类似国际象棋棋盘染色)
因此问题等价于:在剩余格子中,最多能找到多少对相邻的黑 - 白格组合;
二分图构建:
以黑格((i+j) 为偶数的格子)作为二分图左集合,白格((i+j) 为奇数的格子)作为右集合
对每个未被移除的黑格,向其上下左右四个方向的未被移除白格建立边(表示可被同一骨牌覆盖)
最大匹配求解 - 使用匈牙利算法寻找二分图的最大匹配:
对每个黑格尝试通过 DFS 寻找增广路径(交替经过未匹配边和已匹配边的路径)
找到增广路径后翻转路径上的边状态,使匹配数增加 1
重复直至无法找到新的增广路径,此时匹配数达到最大
结果映射
二分图的最大匹配数即为最多能放置的多米诺骨牌数量(每个匹配对应一个骨牌)
注意事项:
参考代码:
#include<bits/stdc++.h> using namespace std; const int N = 1e2 + 10; // 棋盘最大尺寸为100x100,定义数组大小 int g[N][N]; // 标记棋盘格子状态,-1表示被移除的格子 int n, m; // n是棋盘大小,m是被移除的格子数量 // 方向数组,用于遍历上下左右四个相邻格子 int d[4][2] = {{0,1}, {1,0}, {0,-1}, {-1,0}}; int mx; // 存储最大匹配数 int match[N*N]; // 匹配数组,match[v]表示与v匹配的u节点 bool v[N * N]; // 标记数组,用于DFS中避免重复访问 vector<int> adj[N*N]; // 邻接表,存储二分图的边 // 将二维坐标(x,y)转换为一维唯一标识符 int get_id(int x, int y){ return (x - 1) * n + y; // 计算方式确保每个格子有唯一ID } // 匈牙利算法核心:深度优先搜索寻找增广路径 bool dfs(int u){ // 遍历u的所有邻接节点v for(auto t : adj[u]){ if(!v[t]){ // 如果v未被访问过 v[t] = true; // 标记为已访问 // 若v未匹配,或v的匹配节点可以找到其他匹配 if (match[t] == 0 || dfs(match[t])){ match[t] = u; // 将v匹配给u return true; // 找到增广路径,返回成功 } } } return false; // 未找到增广路径,返回失败 } int main() { cin >> n >> m; // 输入棋盘大小和被移除的格子数量 // 标记被移除的格子 for(int i = 1; i <= m; ++ i){ int x, y; cin >> x >> y; g[x][y] = -1; // 用-1标记该格子已被移除 } // 构建二分图:只处理黑格((i+j)为偶数),并连接相邻的白格 for(int i = 1; i <= n; ++ i){ for(int j = 1; j <= n; ++ j){ // 只处理未被移除的黑格 if((i + j) % 2 == 0 && g[i][j] != -1){ // 遍历四个方向的相邻格子 for(int k = 0; k < 4; ++ k){ int nx = i + d[k][0]; // 新行坐标 int ny = j + d[k][1]; // 新列坐标 // 检查相邻格子是否在棋盘范围内且未被移除 if(nx >= 1 && nx <= n && ny >= 1 && ny <= n && g[nx][ny] != -1) // 向邻接表添加边:当前黑格 -> 相邻白格 adj[get_id(i,j)].push_back(get_id(nx, ny)); } } } } // 计算二分图的最大匹配 for(int i = 1; i <= n; ++ i){ for(int j = 1; j <= n; ++ j){ // 对每个未被移除的黑格尝试寻找匹配 if((i + j) % 2 == 0 && g[i][j] != -1){ memset(v, 0, sizeof v); // 重置访问标记 if(dfs(get_id(i,j))) // 找到增广路径,匹配数+1 mx += 1; } } } // 最大匹配数即为最多能放置的多米诺骨牌数量 cout << mx; return 0; }
0.0分
0 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复