1.2维数组基础 2.2维数组的图形表示

登录以参加训练计划

二维数组问题解读思路与方法论

针对CSP-J竞赛中二维数组问题的系统性解决策略

问题解读的通用框架

解题步骤流程图

1. 理解问题 → 2. 分析输入输出 → 3. 识别数据结构
       ↓
4. 确定处理模式 → 5. 设计算法步骤 → 6. 处理边界情况
       ↓
7. 测试验证

1. 基础应用问题解读思路

1.1 求各科平均分

问题本质:矩阵的列统计问题

解决思路

  1. 识别数据结构:学生为行,课程为列的二维矩阵
  2. 处理模式:列优先遍历
  3. 算法步骤:
    • 外层循环遍历课程(列)
    • 内层循环遍历学生(行),计算当前列的总和
    • 总和除以学生数得到平均分
  4. 边界:无特殊边界
  5. 优化:使用浮点数保存平均分

代码框架

for (int j = 0; j < COURSES; j++) {
    double sum = 0;
    for (int i = 0; i < STUDENTS; i++) {
        sum += scores[i][j];
    }
    double avg = sum / STUDENTS;
    cout << "课程" << j+1 << "平均分:" << avg << endl;
}

1.2 杨辉三角

问题本质:递推关系可视化问题

解决思路

  1. 关键特性:每个数等于它上方两数之和
  2. 处理模式:分层填充
  3. 算法步骤:
    • 初始化第一列和对角线为1
    • 从第三行开始,中间元素 = 左上元素 + 正上元素
  4. 边界:第一列和对角线初始化为1
  5. 输出技巧:使用空格居中对齐

递推公式

a[i][0] = 1
a[i][i] = 1
a[i][j] = a[i-1][j-1] + a[i-1][j]  (当i>=2且1<=j<i)

1.3 图形相似度

问题本质:矩阵比较问题

解决思路

  1. 数据结构:两个相同尺寸的二维矩阵
  2. 处理模式:元素级比较
  3. 算法步骤:
    • 遍历每个位置(i,j)
    • 比较两个矩阵在(i,j)的值
    • 统计相同元素的个数
    • 计算相同元素比例
  4. 注意:避免整数除法

伪代码

same_count = 0
total = ROWS * COLS

for i from 0 to ROWS-1:
    for j from 0 to COLS-1:
        if matrixA[i][j] == matrixB[i][j]:
            same_count++
            
similarity = (same_count / total) * 100

1.4 操场换位置

问题本质:矩阵行列变换问题

解决思路

  1. 操作分解:行交换和列交换独立
  2. 算法步骤:
    • 行交换:遍历指定行的每一列,交换元素
    • 列交换:遍历指定列的每一行,交换元素
  3. 注意:交换操作使用标准swap函数

操作步骤

// 交换第r1行和第r2行
for j=0 to COLS-1:
    swap(matrix[r1][j], matrix[r2][j])
    
// 交换第c1列和第c2列
for i=0 to ROWS-1:
    swap(matrix[i][c1], matrix[i][c2])

2. 图形应用问题解读思路

2.1 对角线处理

问题本质:矩阵特殊位置识别问题

解决思路

  1. 模式识别:
    • 主对角线:i == j
    • 副对角线:i + j == N-1
  2. 算法步骤:
    • 遍历每个位置(i,j)
    • 根据位置是否在对角线上设置值

代码框架

for (int i=0; i<N; i++) {
    for (int j=0; j<N; j++) {
        if (i == j) 
            // 主对角线操作
        if (i+j == N-1) 
            // 副对角线操作
    }
}

2.2 数字走向(螺旋矩阵)

问题本质:路径规划问题

解决思路

  1. 模式:螺旋填充(右→下→左→上)
  2. 关键:四边界法(top, bottom, left, right)
  3. 算法步骤:
    • 初始化四个边界和计数器
    • 循环执行四个方向填充,每次缩小边界
    • 终止条件:计数器达到N*N

填充流程

1. 向右填充顶行:left→right, 然后top++
2. 向下填充右列:top→bottom, 然后right--
3. 向左填充底行:right→left, 然后bottom--
4. 向上填充左列:bottom→top, 然后left++

2.3 斜角填充

问题本质:对角线顺序填充问题

解决思路

  1. 模式:按对角线填充(左上到右下)
  2. 数学:每条对角线上 i+j 为常数
  3. 算法步骤:
    • 外层循环:对角线编号d(0到2*N-2)
    • 内层循环:行号i(0到N-1)
    • 列号j = d - i
    • 检查j是否在[0, N-1]内

伪代码

num = 1
for d=0 to 2*N-2:
    for i=0 to N-1:
        j = d - i
        if j >=0 and j < N:
            matrix[i][j] = num++

2.4 拐角处理

问题本质:矩阵边界识别问题

解决思路

  1. 区域划分:角点、边缘、内部
  2. 算法步骤:使用条件分支处理不同区域

条件判断框架

if (i==0 && j==0) // 左上角
else if (i==0 && j==N-1) // 右上角
else if (i==N-1 && j==0) // 左下角
else if (i==N-1 && j==N-1) // 右下角
else if (i==0) // 上边缘(不含角)
else if (i==N-1) // 下边缘(不含角)
else if (j==0) // 左边缘(不含角)
else if (j==N-1) // 右边缘(不含角)
else // 内部

2.5 鲜花方阵

问题本质:模式识别与区域划分问题

解决思路

  1. 区域:
    • 花蕊:中心矩形区域
    • 花瓣:棋盘格位置((i+j)%2==0)且不在花蕊区
    • 背景:其余位置
  2. 算法步骤:使用嵌套条件判断

伪代码

for i in range(N):
    for j in range(N):
        if (i在花蕊行范围 and j在花蕊列范围):
            设置花蕊符号
        else if ((i+j)%2 == 0):
            设置花瓣符号
        else:
            设置背景符号

通用解题方法论

二维数组问题解决四步法

  1. 问题分析

    • 明确输入输出格式
    • 理解问题核心要求
    • 识别关键操作(填充、变换、统计等)
  2. 结构识别: | 特征 | 识别方法 | 示例问题 | |------|----------|----------| | 行列结构 | 明确行数列数 | 各科平均分 | | 对称性 | 检查i,j关系 | 对角线处理 | | 区域划分 | 坐标范围判断 | 鲜花方阵 | | 路径特性 | 分析移动方向 | 螺旋矩阵 |

  3. 模式提取

    graph LR
    A[遍历模式] --> B[行优先]
    A --> C[列优先]
    A --> D[对角线顺序]
    A --> E[螺旋顺序]
    
    F[填充规则] --> G[固定值]
    F --> H[递推计算]
    F --> I[位置相关]
    
  4. 算法设计

    • 选择合适的数据结构
    • 设计核心处理逻辑
    • 处理边界情况
    • 优化时间和空间复杂度

调试技巧表

问题类型 调试策略 示例
边界错误 输出边界元素值 检查第0行和最后一行
逻辑错误 缩小规模测试 使用3x3矩阵测试
越界访问 添加边界检查 if(i>=0 && i<ROWS)
值错误 输出中间结果 填充过程中输出矩阵

常见错误及预防

1. 行列混淆
   预防:明确命名 rows/cols,i行j列

2. 越界访问
   预防:循环条件使用 < 而不是 <=

3. 边界处理遗漏
   预防:单独测试边界情况

4. 嵌套循环变量误用
   预防:内外层使用不同变量名(i,j)

5. 初始化遗漏
   预防:声明后立即初始化

实战思维训练

问题解读训练题

题目:N×N矩阵,将外围元素顺时针旋转90度

解读思路

  1. 分析:只处理外围元素,内部不变
  2. 结构:分层处理,外层→内层
  3. 模式:四个边的元素轮换位置
  4. 算法:
    for 层数layer从0到N/2-1:
        保存顶部行 → 右侧列
        右侧列 → 底部行
        底部行 → 左侧列
        左侧列 → 顶部行
    

综合应用框架

#include <iostream>
using namespace std;

const int N = 5; // 矩阵尺寸

int main() {
    // 1. 初始化矩阵
    int matrix[N][N];
    
    // 2. 填充初始数据
    // ...
    
    // 3. 核心操作(根据问题选择)
    // - 行列交换
    // - 螺旋填充
    // - 对角线处理
    // - 区域划分
    
    // 4. 输出结果
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            cout << matrix[i][j] << " ";
        }
        cout << endl;
    }
    
    return 0;
}

学习建议

  1. 从简单开始:先解决3x3小矩阵问题
  2. 可视化思考:在纸上画出矩阵索引
  3. 分步调试:复杂算法分阶段实现
  4. 模式积累:收集常见问题处理模式
  5. 边界测试:专门测试边界情况
  6. 代码复用:建立个人代码库

"二维数组问题如同棋盘游戏,掌握行列坐标的奥秘,就能解开所有矩阵谜题!"

思维导图总结

二维数组问题解决
├── 问题分析
│   ├── 输入格式
│   ├── 输出要求
│   └── 核心操作
├── 结构识别
│   ├── 行列结构
│   ├── 对称性
│   ├── 区域划分
│   └── 路径特性
├── 模式提取
│   ├── 遍历模式
│   ├── 填充规则
│   └── 变换类型
└── 算法设计
    ├── 数据结构
    ├── 核心逻辑
    ├── 边界处理
    └── 复杂度优化

章节 1. 二维数组基础

开放

题目 尝试 AC 难度
P241   【入门】求各个科目成绩的平均分 5 1 10
P242   【入门】输出杨辉三角的前N行 6 1 10
960   【入门】地雷数量求解 2 1 10
861   【入门】图像相似度? 0 0 (无)
776   【入门】求最大梯形的面积 1 1 10
836   【入门】靶心数 0 0 (无)
851   【入门】奇偶统计? 0 0 (无)
856   【入门】找回文数 0 0 (无)
860   【入门】石头剪刀布? 0 0 (无)
P579   【入门】求六位整数的各个位 0 0 (无)
P920   【入门】每个小组的最大年龄 0 0 (无)
P921   【入门】孤独的素数 0 0 (无)
P922   【入门】找朋友 0 0 (无)
P923   【入门】操场换位置 0 0 (无)

章节 2. 二维数组图形

开放

题目 尝试 AC 难度
620   【入门】对角线I 0 0 (无)
621   【入门】对角线II 0 0 (无)
614   【入门】数字走向I 0 0 (无)
615   【入门】数字走向II 0 0 (无)
616   【入门】数字走向III 0 0 (无)
617   【入门】数字走向IV 0 0 (无)
622   【入门】斜角I 0 0 (无)
623   【入门】斜角II 0 0 (无)
625   【入门】斜角III 0 0 (无)
626   【入门】斜角IV 0 0 (无)
654   【入门】有趣的数字图形II 0 0 (无)
629   【入门】拐角III 0 0 (无)
648   【入门】拐角IV 0 0 (无)
649   【入门】拐角V 0 0 (无)
653   【入门】有趣的数字图形I 0 0 (无)
655   【入门】有趣的数字图形III 0 0 (无)
656   【入门】有趣的数字图形IV 0 0 (无)
837   【入门】有趣的数字图形 0 0 (无)
773   【入门】鲜花方阵 0 0 (无)