题目描述
扫雷游戏是一款十分经典的单机小游戏。在 n 行 m 列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格)。玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有多少个是地雷格。游戏的目标是在不翻出任何地雷格的条件下,找出所有的非地雷格。
现在给出 n 行 m 列的雷区中的地雷分布,要求计算出每个非地雷格周围的地雷格数。
注:一个格子的周围格子包括其上、下、左、右、左上、右上、左下、右下八个方向上与之直接相邻的格子。
输入格式
第一行是用一个空格隔开的两个整数 n 和 m,分别表示雷区的行数和列数。
接下来 n 行,每行 m 个字符,描述了雷区中的地雷分布情况。字符 ** 表示相应格子是地雷格,字符 ?? 表示相应格子是非地雷格。相邻字符之间无分隔符。
输出格式
输出文件包含 n 行,每行 m 个字符,描述整个雷区。用 ** 表示地雷格,用周围的地雷个数表示非地雷格。相邻字符之间无分隔符。
输入输出样例
输入 #1复制
3 3 *?? ??? ?*?
输出 #1复制
*10 221 1*1
输入 #2复制
2 3 ?*? *??
输出 #2复制
2*1 *21
说明/提示
对于 100%的数据,1≤ n ≤100,1≤ m ≤100。
题解代码如下:
#include <iostream>
using namespace std;
const int dx[] = {1, 1, 1, 0, 0, -1, -1, -1};
const int dy[] = {-1, 0, 1, -1, 1, -1, 0, 1};
char g[105][105];
int n, m;
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) //从1开始读,代表在地雷阵周边加上了一个空白边框,防止数组越界
for (int j = 1; j <= m; j++)
cin >> g[i][j]; //读入地雷阵
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
if (g[i][j] != '*') {
int cnt = 0;
for (int k = 0; k < 8; k++)
if (g[i + dx[k]][j + dy[k]] == '*') cnt++; //用循环代替八条if语句判断该点周围是否有地雷
cout << cnt;
}
else cout << "*"; //若该点为地雷,直接输出即可
cout << endl;
}
return 0;
}
本题难点并不在于如何输入地雷阵,而是如何在代码后半部分的循环中逐个判断地雷阵中的地雷,以及非地雷位周围的地雷数量。
尤其是在地雷阵的边界,若直接采用双重for循环进行数组遍历,再逐个判断,可能造成数组越界。因此,一个处理方式就是开二维数组时在整个地雷阵外围多开一圈,全部置为非地雷位。
这样处理后,可以在遍历数组时不必额外处理地雷阵边界的点。
另外一个值得学习的地方是代码开头定义的两个一维数组,他的意义在于当我们判断地雷阵中每一个位置周围的地雷情况时,可以不用写八条if语句来判断周围是否存在地雷,而是可以直接通过一个for循环来判断(通过改变i、j的值),这样可以大大缩短代码长度,增加代码的可读性。
以后类似用二维数组处理的模拟题,都可以参考此题的解题思路和某些地方的处理(比如数组边界、判断某一点周围的情况等),这样可以大大缩短代码长度。
以上。