⌛️ 闲来无事碧溪上,忽复扫雷用 C C C 编
扫雷 ☁️
百题打卡总目录: …
● 在一个 n n n 行 m m m 列的方格图上有一些位置有地雷,另外一些位置为空。请为每个空位置标一个整数,表示周围八个相邻的方格中有多少个地雷。
● 输入描述:
① 第 1 1 1 行输入包含两个整数 n n n、 m m m
② 第 2 2 2 行到第 n + 1 n + 1 n+1 行每行包含 m m m 个整数,相邻整数之间用一个空格分隔。
③ 如果对应的整数为 0 0 0,表示这一格没有地雷。如果对应的整数为 1 1 1,表示这一格有地雷。
注意:其中, 1 ≤ n , m ≤ 100 1≤n,m≤100 1≤n,m≤100。运行限制——>最大运行时间: 1 s 1s 1s,最大运行内存: 128 M 128M 128M
● 输出描述:
① 输出 n n n 行,每行 m m m 个整数,相邻整数之间用空格分隔。
② 对于没有地雷的方格,输出这格周围的地雷数量。对于有地雷的方格,输出 9 9 9。
● 输入样例:
3 4
0 1 0 0
1 0 1 0
0 0 1 0
● 输出样例:
2 9 2 1
9 4 9 2
1 3 9 2
● 题目难度:⭐️⭐️
● 建议思考时间:⌛️
● 这是一道模拟题
(顾名思义,就是我们要用代码,模拟并呈现出题目中要求的效果)
● 算法设计:
[1]
设计好 输入输出机制。(明确要输入什么,要输出什么)
[2]
设计好 遍历机制。一排一排地扫。当扫到1
(雷)时,直接输出9
。若扫到0
,则看它周围8
个框框共有几个1
(雷),输出该雷数。
[3]
注意细节——边界处理机制【这是刚刷题时常犯的 Bug,我这次也反了,写出来长几个记性】
● 这是手到擒来的事:
#include
int main()
{
int n, m, i, j;
int a[110][110]={0}; // 因为题目的要求是 1≤n,m≤100, 所以我们只要设定的大一点就行
scanf("%d%d", &n, &m);
for ( i = 0; i < n; i++ )
for ( j = 0; j < m; j++ )
scanf("%d", &a[i][j]); // 读入方格图
// ...写入相关算法
for ( i = 0; i < n; i++ )
{
for ( j = 0; j < m; j++ )
{
printf(...);
}
printf("\n"); // 换行
}
return 0;
}
● 一般,最先想到的遍历方法如下。【注:dx[]
和dy[]
在后面的代码中有说明。】
#include
int main()
{
/* 输入机制 */
...
/* 在输出机制上引入遍历机制 */
int dx[8] = { 0, 1, 1, 1, 0, -1, -1, -1}; // dx: 类似于高数里面的微分, 在代码界, 其含义就是在 “行” 这个方向的最小变化单位
int dy[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; // dy: 同理, 在代码界, 其含义就是在 “列” 这个方向的最小变化单位
int cnt = 0; // count 的缩写(代码界, 计数器的意思)
for ( i = 0; i < n; i++ )
{
for ( j = 0; j < m; j++ )
{
if ( a[i][j] == 1 )
{
printf("9 ");
continue;
}
cnt = 0;
for (int k = 0; k < 8; k++)
{
int new_i = i + dx[k];
int new_j = j + dy[k];
if ( a[new_i][new_j] == 1 )
cnt++;
}
printf("%d ", cnt);
}
printf("\n");
}
return 0;
}
● 当敲到这里,我信心慢慢地提交代码时,诶,样例都不能通过。经过一番检查,发现是老生常谈的越界问题未解决。
● 试想,如果扫到的数字的当前下标为(0,5)
,那么当k=0
时,就要去判断a[-1][5]
是否等于0
。显然下标越界了。只要想到这一点,还是很快就能搞定。解决代码如下:
#include
int main()
{
/* 输入机制 */
...
/* 在输出机制上引入遍历机制 */
...
for ( i = 0; i < n; i++ )
{
for ( j = 0; j < m; j++ )
{
if ( a[i][j] == 1 )
{...}
cnt = 0;
for (int k = 0; k < 8; k++)
{
int new_i = i + dx[k];
int new_j = j + dy[k];
+------------------------------------------------------------------------+
if ( new_i < 0 || new_j < 0 || new_i >= n || new_j >= m ) // 新加的代码
continue;
+------------------------------------------------------------------------+
if ( a[new_i][new_j] == 1 )
cnt++;
}
printf("%d ", cnt);
}
printf("\n");
}
return 0;
}
● 当敲到这里,我再次信心慢慢地提交代码时,诶,✅
● 熟悉了一下模拟机制——通过开设dx[]
和dy[]
数组来模拟地雷一圈的下标偏移位置。
● 数组的越界是老生常谈的问题,以后再做类似的问题时,要多加注意。
● C 语言版本:
#include
int main()
{
/* 输入机制 */
int n, m, i, j;
int a[110][110]={0}; // 因为题目的要求是 1≤n,m≤100, 所以我们只要设定的大一点就行
scanf("%d%d", &n, &m);
for ( i = 0; i < n; i++ )
for ( j = 0; j < m; j++ )
scanf("%d", &a[i][j]); // 读入方格图
/* 在输出机制上引入遍历机制 */
int dx[8] = { 0, 1, 1, 1, 0, -1, -1, -1}; // dx: 类似于高数里面的微分, 在代码界, 其含义就是在 “行” 这个方向的最小变化单位
int dy[8] = {-1, -1, 0, 1, 1, 1, 0, -1}; // dy: 同理, 在代码界, 其含义就是在 “列” 这个方向的最小变化单位
int cnt = 0; // count 的缩写(代码界, 计数器的意思)
for ( i = 0; i < n; i++ )
{
for ( j = 0; j < m; j++ )
{
if ( a[i][j] == 1 )
{
printf("9 ");
continue;
}
cnt = 0;
for (int k = 0; k < 8; k++)
{
int new_i = i + dx[k];
int new_j = j + dy[k];
if (new_i < 0 || new_j < 0 || new_i >= n || new_j >= m) // 边界处理机制
continue;
if ( a[new_i][new_j] == 1 )
cnt++;
}
printf("%d ", cnt);
}
printf("\n");
}
return 0;
}
● 运行结果:
● C++ 版本:
#include
using namespace std;
int main()
{
/* 输入机制 */
int n, m, cnt;
int a[110][110] = { 0 };
cin >> n >> m;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cin >> a[i][j];
}
}
/* 在输出机制上引入遍历机制 */
int dx[8] = { 0, 1, 1, 1, 0, -1, -1, -1};
int dy[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
if (a[i][j] == 1)
{
cout << 9 << " ";
continue;
}
cnt = 0;
for (int k = 0; k < 8; k++)
{
int new_i = i + dx[k];
int new_j = j + dy[k];
if (new_i < 0 || new_j < 0 || new_i >= n || new_j >= m) // 边界处理机制
continue;
if ( a[new_i][new_j] == 1 )
cnt++;
}
cout << cnt << " ";
}
cout << endl;
}
return 0;
}
[1] 原题地址:https://www.lanqiao.cn/problems/549/learning/.
百题打卡总目录: …
C/C++百日打卡[1/100]——扫雷 [题目源自 2021 蓝桥杯] ⭐️ ⭐️
标签: 模拟, 数组, 暴力, 2021, 模拟赛
三日一更
2021/11/29