【2024GXOI进阶】扫雷(minesweeper)
解题思路
-
问题分析:
-
给定一个扫雷棋盘,包含数字(0-8)、地雷(*)和未知位置(?)
-
需要确定是否存在一种将?替换为或非的方式,使得所有数字格周围的地雷数与其数字相符
-
-
关键步骤:
-
收集所有未知位置(?)
-
使用深度优先搜索(DFS)尝试所有可能的?位置组合(放置地雷或不放置)
-
对每种组合检查整个棋盘的合法性
-
-
优化考虑:
-
题目保证?的数量≤10,DFS的时间复杂度可行(2^10=1024种可能)
-
提前终止:一旦找到合法解立即返回
-
#include<bits/stdc++.h> #define pii pair<int,int> // 定义pair<int,int>的简写 using namespace std; const int N = 1e3 + 10; // 定义棋盘最大尺寸 char g[N][N]; // 存储棋盘 vector<pii> v; // 存储所有'?'的位置 int nex[8][2] = {{0,1},{1,0},{0,-1},{-1,0},{-1,-1},{-1,1},{1,-1},{1,1}}; // 八个方向 int n,m,f; // n行m列,f标记是否找到合法解 // 检查当前棋盘是否合法 bool check() { for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { // 只检查数字格子 if(g[i][j] != '*' && g[i][j] != '?') { int sum = 0,x = g[i][j] - '0'; // sum统计周围地雷数,x是当前数字 // 检查八个方向 for(int k = 0; k < 8; k++) { int tx = i + nex[k][0]; int ty = j + nex[k][1]; // 越界检查 if(tx < 1 || tx > n || ty < 1 || ty > m) continue; if(g[tx][ty] == '*') sum++; } // 如果地雷数与数字不符,返回不合法 if(x != sum) return 0; } } return 1; // 所有数字格子都合法 } // 深度优先搜索尝试所有可能的'?'组合 void dfs(int k) { if(f) return; // 如果已经找到解,提前返回 if(k == v.size()) // 所有'?'都已处理 { f = check(); // 检查当前棋盘 return; } int x = v[k].first,y = v[k].second; // 尝试在该位置放置地雷 g[x][y] = '*'; dfs(k + 1); // 尝试在该位置不放置地雷(恢复为'?') g[x][y] = '?'; dfs(k + 1); } int main() { int t; cin >> t; // 测试用例数量 while(t--) { memset(g,0,sizeof(g)); // 清空棋盘 v.clear(); // 清空'?'位置记录 cin >> n >> m; // 读入棋盘并记录'?'位置 for(int i = 1; i <= n; i++) for(int j = 1; j <= m; j++) { cin >> g[i][j]; if(g[i][j] == '?') v.push_back({i,j}); } f = 0; // 初始化未找到解 dfs(0); // 从第一个'?'开始搜索 if(f) cout << "YES" << endl; else cout << "NO" << endl; } return 0; }
代码执行流程
-
读取测试用例数量T
-
对于每个测试用例:
-
清空棋盘和'?'位置记录
-
读取棋盘尺寸n,m
-
读取棋盘内容并记录所有'?'的位置
-
初始化未找到解标志f=0
-
调用dfs(0)开始搜索
-
根据f的值输出YES或NO
-
算法特点
-
DFS回溯:通过DFS尝试所有可能的'?'组合
-
剪枝优化:一旦找到合法解立即终止搜索
-
方向处理:使用8方向数组处理周围格子的检查
-
边界检查:在检查周围格子时进行越界判断
该算法充分利用了题目中'?'数量≤10的限制,使得DFS可以在合理时间内完成搜索。

浙公网安备 33010602011771号