蓝桥杯—OJ549扫雷问题(贪心算法)

题目:

在一个n行m列的方格图上有一些位置有地雷,另外一些位置为空。

请为每个空位置标一个整数,表示周围八个相邻的方格中有多少个地雷。

【输入】

输入的第一行包含两个整数n,m。

第2行到第n+1行每行包含m个整数,相邻整数之间用一个空格分隔。如果对应的整数为0,表示这一格没有地雷。如果对应的整数为1,表示这一格有地雷。

其中,1≤n,m≤100。

【输出】

输出n行,每行m个整数,相邻整数之间用空格分隔。

对于没有地雷的方格,输出这格周围的地雷数量。对于有地雷的方格,输出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

答案:

#include <bits/stdc++.h> 

using namespace std; 

int main()
{
    int n, m, cnt;  // 声明整数 n, m 用于表示二维数组的行和列,cnt 用于计数
    int a[110][110] = { 0 }; // 初始化一个 110x110 的二维数组,所有元素都设置为 0

    cin >> n >> m; // 从标准输入读取 n(行数)和 m(列数)

    // 使用输入的值填充二维数组
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> a[i][j]; // 将每个元素读入数组
        }
    }

    // 定义数组以表示 8 个相邻单元格的相对位置
    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) // 如果当前单元格的值为 1
            {
                cout << 9 << " "; // 打印 9 和一个空格(具体问题的规则可能会要求这样做)
                continue; // 继续下一次迭代
            }
            cnt = 0; // 重置邻近的 1 的计数

            // 循环遍历 8 个方向
            for (int k = 0; k < 8; k++)
            {
                int new_i = i + dx[k]; // 通过添加第 k 个 dx 值计算新的 i 坐标
                int new_j = j + dy[k]; // 通过添加第 k 个 dy 值计算新的 j 坐标

                // 如果新坐标在数组边界之外,继续下一次循环
                if (new_i < 0 || new_j < 0 || new_i >= n || new_j >= m)		
                    continue;
                
                // 如果相邻单元格包含 1,则增加计数
                if (a[new_i][new_j] == 1)
                    cnt++;
            }
            cout << cnt << " "; // 打印该单元格的邻近 1 的计数和一个空格
        }
        cout << endl; // 在处理完一行后,输出换行符
    }
    return 0; 
}

注:

  • int dx[8] = { 0, 1, 1, 1, 0, -1, -1, -1 };
  • int dy[8] = {-1, -1, 0, 1, 1, 1, 0, -1 };

这里,dxdy 数组代表一个单元格相对于其八个可能的邻近单元格的位置偏移:上,右上,右,右下,下,左下,左和左上。

例如,第一个 dx[0], dy[0] 对表示向右移动零列dx[0])和向上移动一行dy[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;

    // 如果相邻单元格包含 1,增加计数。
    if (a[new_i][new_j] == 1)
        cnt++;
}

程序对于不是 1 的每个单元格 a[i][j] 执行以下操作:

  1. 循环通过 dx 和 dy 数组查看每一个邻近的 8 个单元格。
  2. 计算 new_i 和 new_j,它们是这些邻居之一的坐标。
  3. 检查是否 new_i 或 new_j 超出了数组的边界。如果是,跳转到下一个邻居。
  4. 如果邻居单元格在边界内且含有 1,增加计数 1 的数量。

遍历所有 8 个可能邻居后,它会打印出该单元格的计数。

例如,如果当前单元格 a[i][j] 在网格中的坐标是 [2,2],那么遍历 k 的循环将检查 [2,1](上),[3,1](右上)...等单元格。如果位置有效并且单元格内容是 1,就会增加该单元格的计数。

最后,当 j 上的内层循环完成后(表示一行的结束),会打印出一个换行符来正确格式化输出,分隔各行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值