C/C++百题打卡[1/100]——扫雷


⌛️ 闲来无事碧溪上,忽复扫雷用 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 1n,m100。运行限制——>最大运行时间: 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,我这次也反了,写出来长几个记性】


3.1 第[1]步:输入输出机制

  ● 这是手到擒来的事

#include <stdio.h>
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;
}


3.2 第[2]步:遍历机制

  ● 一般,最先想到的遍历方法如下。【注:dx[]dy[]在后面的代码中有说明。】

在这里插入图片描述
  ● 代码如下

#include <stdio.h>
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;
}

  ● 当敲到这里,我信心慢慢地提交代码时,诶,样例都不能通过。经过一番检查,发现是老生常谈的越界问题未解决。


3.3 第[3]步:边界处理机制

  ● 试想,如果扫到的数字的当前下标为(0,5),那么当k=0时,就要去判断a[-1][5]是否等于0。显然下标越界了。只要想到这一点,还是很快就能搞定。解决代码如下:

#include <stdio.h>
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和C++版)

  ● C 语言版本:

#include <stdio.h>
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 <iostream>
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

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一支王同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值