[BFS]529. Minesweeper

本文详细解析了一个扫雷游戏的算法实现过程,包括如何通过递归方法更新游戏板面状态,以及具体的边界检测和条件判断等关键技术细节。

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

【记又一次阵亡在“==”上的惨痛经历微笑

题目:

Let's play the minesweeper game (Wikipedia, online game)!

You are given a 2D char matrix representing the game board. 'M' represents an unrevealed mine, 'E' represents an unrevealed empty square, 'B' represents a revealed blank square that has no adjacent (above, below, left, right, and all 4 diagonals) mines, digit ('1' to '8') represents how many mines are adjacent to this revealed square, and finally 'X' represents a revealed mine.

Now given the next click position (row and column indices) among all the unrevealed squares ('M' or 'E'), return the board after revealing this position according to the following rules:

  1. If a mine ('M') is revealed, then the game is over - change it to 'X'.
  2. If an empty square ('E') with no adjacent mines is revealed, then change it to revealed blank ('B') and all of its adjacent unrevealed squares should be revealed recursively.
  3. If an empty square ('E') with at least one adjacent mine is revealed, then change it to a digit ('1' to '8') representing the number of adjacent mines.
  4. Return the board when no more squares will be revealed.

Example 1:

Input: 

[['E', 'E', 'E', 'E', 'E'],
 ['E', 'E', 'M', 'E', 'E'],
 ['E', 'E', 'E', 'E', 'E'],
 ['E', 'E', 'E', 'E', 'E']]

Click : [3,0]

Output: 

[['B', '1', 'E', '1', 'B'],
 ['B', '1', 'M', '1', 'B'],
 ['B', '1', '1', '1', 'B'],
 ['B', 'B', 'B', 'B', 'B']]

Explanation:

题目分析:

1、根据题目,要求是根据给出的矩阵(包含地雷标记M,和未点开标记E)和输入的点击位置,按要求得出点击后的矩阵并返回。

2、对于点击后的显示规则,大概有三类:①如果是雷,直接标记为X并结束;②如果不是雷且周围有雷,那么将这一格标记为周围雷的数量;③如果不是雷且周围也没有雷,那么就标记为B并递归地继续点开周围标记为E的格子。

3、很容易发现这道题的解决是利用递归的方法,且根据递归的条件容易发现所有的B应该都是连通的,不然没法被递归打开。

4、对于此题的解决算法。考虑先检验这个格子的属于2中的哪个类型,即首先检验是否为M,其次检验是否周围有M,如果都不是则为B且开始递归。至于将递归放在最后的原因,是为了避免在某个格子周围有雷的时候仍然要打开其它E的情况。

5、具体在代码实现中有两个问题。①检验顺序。解决方法前面已经介绍了;②边界检测。由于中间的格子和矩阵边界的格子要打开(检测)的格子(如果要打开)情况不同,那么如果利用循环来遍历周围的八个格子,就必须检测行列参数是否越界。

代码实现:

void func(vector<vector<char>>& board, int row, int col){
	if(board[row][col] == 'M') {
		board[row][col] = 'X';
		return;
	}
	else{
		int count = 0;
		bool checkM = 0;
		int i = row - 1;
		int j = col - 1;
		if(i < 0) i = 0;
		if(j < 0) j = 0;
		for(; i <= row + 1; i++){
			if(i == board.size())
				break; 
			for(int j = col - 1; j <= col + 1; j++){
				if(j == board[0].size())
					break;
				if(i == row && j == col)
					continue;
				if(board[i][j] == 'M'){
					checkM = 1;
					count ++;
				}
			}
		}
		if(checkM == 1){
			board[row][col] = count + '0';
			return;
		}
		board[row][col] = 'B';
		int i = row - 1;
		int j = col - 1;
		if(i < 0) i = 0;
		if(j < 0) j = 0;
		for(; i <= row + 1; i++){
			if(i == board.size())
				break; 
			for(int j = col - 1; j <= col + 1; j++){
				if(j == board[0].size())
					break;
				if(i == row && j == col)
					continue;
				if(board[i][j] == 'E')	
					func(board, i, j);
			}
		}
	}
}
class Solution {
public:
    vector<vector<char>> updateBoard(vector<vector<char>>& board, vector<int>& click) {
        func(board, click[0], click[1]);
		return board;
    }
};

总结与经验:

1、在开始编写代码之前一定要对整个题目要求有清晰明确的认识。我在刚开始完成这道题的时候并没有注意到如果某个格子周围有雷它就不会去打开周围没有被打开的格子,这导致我在考虑递归的时候是把标记B和数字的格子统一起来的,这就导致发现了问题后要纠正代码时工作量很大;

2、要学会利用错误的答案分析问题所在。在最后几次提交代码测试的时候发现标记B能正常递归,但是本该标记数字的格子却没有变化,然而结果却显示程序在运行途中是知道这个格子应该被标记数字的(因为程序中设置了bool变量来检测)。但是为什么既然检测出来了却并没有任何操作呢?这个问题困扰了我很久很久很久.....甚至最后我都放弃debug了。好在睡了一觉后爬起来继续看了看代码,突然发现检测出周围有M后对本格子的赋值操作是“==”(本来该是“=”)........呵呵,又是熟悉的情景。






<think>根据用户的问题,用户遇到了编译错误:bfs/SbusRx.h file not found。这是一个典型的头文件缺失问题,通常发生在编译过程中编译器无法找到指定的头文件。 解决方案思路: 1. 确认头文件是否存在:检查bfs/SbusRx.h文件是否在项目中或系统中。 2. 检查头文件路径:如果头文件存在,需要确保编译器的搜索路径包含了该头文件所在的目录。 3. 检查文件路径大小写:文件系统可能区分大小写,确保路径中的大小写与实际文件匹配。 4. 检查依赖库:如果头文件属于某个库,确保该库已正确安装。 具体步骤: 步骤1:查找头文件 - 在项目目录中搜索bfs/SbusRx.h文件,可以使用系统搜索命令(如find或grep)来定位。 - 如果头文件属于第三方库,请确认该库是否已下载并放置在正确位置。 步骤2:添加包含路径 - 如果头文件在项目目录中,确保在编译命令中使用`-I`选项指定头文件所在目录。 例如,如果头文件位于`/project/include/bfs/SbusRx.h`,则编译命令应包含`-I/project/include`。 - 在Makefile或CMakeLists.txt中设置包含路径。 步骤3:检查文件路径大小写 - 如果项目在区分大小写的文件系统(如Linux)上,确保代码中`#include`语句的路径大小写与实际文件路径一致。 步骤4:安装缺失的库 - 如果头文件属于某个库(如libbfs),则需要安装该库。可以通过包管理器安装,例如: Ubuntu/Debian: `sudo apt-get install libbfs-dev` CentOS/Fedora: `sudo yum install bfs-devel` - 或者从源码编译安装。 步骤5:检查环境变量 - 有时环境变量(如`CPATH`或`C_INCLUDE_PATH`)可以设置头文件搜索路径,确保这些变量包含头文件所在目录。 步骤6:重新生成构建系统(如果使用CMake等) - 如果使用CMake,修改CMakeLists.txt后需要重新生成构建文件。 示例CMakeLists.txt修改: 在`include_directories`中添加头文件路径,例如: ```cmake include_directories(/path/to/directory_containing_bfs) ``` 示例Makefile修改: 在编译标志中添加`-I`选项: ```makefile CFLAGS += -I/path/to/directory_containing_bfs ``` 如果以上步骤无法解决问题,可能需要检查项目配置或依赖关系。 相关问题: 1. 如何检查Linux系统中是否安装了某个库? 2. 如何在CMake中添加非标准路径的头文件目录? 3. 如何设置环境变量来影响编译器搜索路径?</think>### 解决 `bfs/SbusRx.h file not found` 编译错误 当遇到 `bfs/SbusRx.h file not found` 错误时,表示编译器在编译过程中无法找到指定的头文件。以下是逐步解决方案: #### 1. **验证头文件是否存在** - 在项目目录中搜索 `SbusRx.h` 文件: ```bash find . -name "SbusRx.h" # Linux/macOS dir /s /b SbusRx.h # Windows CMD ``` - 如果文件不存在: * 检查是否遗漏下载依赖库(如 BFS 库) * 确认项目是否包含 `bfs` 子模块(需 `git submodule update --init`) #### 2. **检查头文件路径配置** - **编译器选项**:添加头文件搜索路径 ```bash g++ -I/path/to/bfs_directory -o output source.cpp # GCC clang++ -I/path/to/bfs_directory -o output source.cpp # Clang ``` - **CMake 项目**:在 `CMakeLists.txt` 中添加: ```cmake include_directories(${PROJECT_SOURCE_DIR}/path/to/bfs_directory) # 或 target_include_directories(your_target PRIVATE /path/to/bfs_directory) ``` - **Makefile 项目**: ```makefile CFLAGS += -I/path/to/bfs_directory CXXFLAGS += -I/path/to/bfs_directory ``` #### 3. **检查文件路径大小写(重要)** - Linux 文件系统区分大小写: ```bash ls ./bfs | grep -i "sbusrx.h" # 检查实际文件名 ``` - 如果实际文件名为 `sbusrx.h` 或 `SBUSRX.H`,需修改代码: ```cpp #include "bfs/sbusrx.h" // 改为匹配实际文件名 ``` #### 4. **检查依赖库安装** - 如果 `bfs` 是外部库: * 安装开发包: ```bash # Ubuntu/Debian sudo apt-get install libbfs-dev # Fedora/CentOS sudo dnf install bfs-devel ``` * 手动编译安装: ```bash git clone https://github.com/bfs-library/repo.git cd repo mkdir build && cd build cmake .. && make sudo make install ``` #### 5. **环境变量配置** - 设置 `CPATH` 或 `C_INCLUDE_PATH`: ```bash export CPATH=/path/to/bfs_directory:$CPATH # Linux/macOS set CPATH=C:\path\to\bfs_directory;%CPATH% # Windows ``` #### 6. **项目结构验证** 确保目录结构符合预期: ``` project_root/ ├── src/ │ └── main.cpp └── bfs/ # 头文件目录 └── SbusRx.h # 目标头文件 ``` 若结构不符,需移动文件或修改构建脚本。 #### 7. **清理并重建项目** ```bash make clean # Makefile 项目 rm -rf build/ # CMake 项目 cmake -B build -S . && cmake --build build ``` > **典型错误案例**:某开发者将头文件放在 `./libs/bfs` 中,但代码引用为 `#include "bfs/SbusRx.h"`,通过 `g++ -I./libs` 解决路径映射问题[^1]。 --- ### 相关问题 1. 如何让 CMake 自动查找第三方库的头文件路径? 2. Linux 和 Windows 在头文件路径处理上有哪些关键差异? 3. 当编译器报告 `undefined reference to` 错误时应如何排查? 4. 如何为跨平台项目配置统一的头文件包含机制? [^1]: Tutorial: Building a Compiler with MLIR, Amini Mehdi et al. (Google)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值