知识文档更新于 2026-09-14

适合谁、学完能做什么

适合已经会使用变量、分支、循环和一维数组的学习者。学完后,你应该能够:

  • 用 a[i][j] 表示第 i 行、第 j 列的格子。
  • 正确完成二维数组的按行、按列遍历。
  • 把“上、下、左、右”转换为坐标变化。
  • 在移动前判断新坐标是否越界。
  • 处理地图、棋盘、座位表、矩阵和网格状态变化。

前置知识与网站关联

必须掌握变量、条件判断、循环、一维数组和基本输入输出。

对应地图节点:arrays.two(二维数组)、arrays.grid(网格模拟)、arrays.direction(方向移动)、arrays.coords(坐标与边界)、arrays.5855c61cec(模拟)。

配套专题:CSP-J|数学|模拟|。

问题引入

下面的地图有4行5列:

       列0 列1 列2 列3 列4
行0     .   .   #   .   .
行1     .   #   #   .   .
行2     .   .   .   .   #
行3     #   .   .   .   .

a[1][2] 表示第1行、第2列的格子。地图、棋盘和矩阵都可以用这种“行坐标+列坐标”表示。

核心概念与图示

如果网格有 n 行、m 列,合法坐标是:

0 <= 行 < n,0 <= 列 < m

按行遍历:

for (int i = 0; i < n; ++i)
    for (int j = 0; j < m; ++j)
        // 处理 a[i][j]

四方向变化量如下:

方向新行新列
上x-1y
下x+1y
左xy-1
右xy+1

代码可写成:

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

从 (x,y) 走第 k 个方向后,新坐标是 (x+dx[k], y+dy[k])。访问前必须先检查:

0 <= nx && nx < n && 0 <= ny && ny < m

示例问题

给定一个由 # 和 . 组成的网格,求每个格子周围四个方向上有多少个 # 格子。

处理每个格子的过程是:遍历当前格子,依次枚举四个方向,计算相邻坐标,越界就跳过,合法且内容为 # 时计数加一。

算法与正确性

四方向数组恰好生成当前格子的四个相邻位置。边界判断排除了所有非法位置;对每个合法邻居只在内容为 # 时计数,因此得到的数量恰好是四邻域中 # 格子的数量。所有格子都执行同样的过程,整体结果正确。

完整 C++ 示例

语言:C++17。输入 n m 和 n 行网格,输出每个格子的四邻域 # 数量。

#include <iostream>
#include <string>
#include <vector>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;
    vector<string> grid(n);
    for (int i = 0; i < n; ++i) cin >> grid[i];

    const int dx[4] = {-1, 1, 0, 0};
    const int dy[4] = {0, 0, -1, 1};

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            int count = 0;
            for (int k = 0; k < 4; ++k) {
                int ni = i + dx[k];
                int nj = j + dy[k];
                if (ni < 0 || ni >= n || nj < 0 || nj >= m) continue;
                if (grid[ni][nj] == '#') ++count;
            }
            if (j > 0) cout << ' ';
            cout << count;
        }
        cout << '\n';
    }
    return 0;
}

复杂度与适用范围

设网格有 n 行、m 列。每个格子最多检查4个方向,因此时间复杂度为 O(nm),存储网格需要 O(nm) 空间。

适合地图、棋盘、邻域统计、矩阵变换和网格状态更新。如果题目要求从起点走到终点、求最少步数或统计连通区域,还需要 BFS、DFS 或动态规划。

易错点

  1. 行列写反:统一使用 a[行][列],变量名用 i 表示行、j 表示列。
  2. 先访问再判断边界:必须先检查 ni、nj,再访问 grid[ni][nj]。
  3. 四方向误写成八方向:斜对角是否计入,要以题目定义为准。
  4. 边计算边覆盖原状态:如果要求同时更新所有格子,应使用新数组保存下一时刻状态。

配套练习

以下题目来自本地 CSP-J|数学|模拟| 专题,题名、链接和难度已核对。当前内容工作室没有这些题的已发布题解,均只提供原题入口。

基础

  1. P7186:[CRCI2008-2009] TABLICA(普及):练习矩阵行列处理和规则化输出。
  2. P3392:涂条纹(普及-):练习二维网格中的区域统计。

变式

  1. P1056:[NOIP 2008 普及组] 排座椅(普及):练习二维关系到行、列统计的转换。
  2. P9582:「MXOI Round 1」方格(普及-):练习方格坐标、邻接关系和边界处理。

综合

  1. P11228:[CSP-J 2024] 地图探险(普及-):综合练习地图、方向移动、状态记录和边界判断。

自查与小结

完成本篇后,应能回答:a[i][j] 中哪个下标是行?如何表示四方向?为什么必须先判断边界?四方向和八方向有什么区别?为什么同时更新网格时通常要用新数组?

能够独立写出二维数组遍历、四方向移动和边界判断,并完成两道基础题和一道综合题,就可以继续学习网格 DFS/BFS 或二维前缀和。

打开学习地图打开配套题单返回文档中心