[蓝桥杯]螺旋矩阵
问题描述
对于一个 nn 行 mm 列的表格,我们可以使用螺旋的方式给表格依次填上正整数,我们称填好的表格为一个螺旋矩阵。
例如,一个 4 行 5 列的螺旋矩阵如下:
1 2 3 4 514 15 16 17 613 20 19 18 712 11 10 9 8
输入描述
输入的第一行包含两个整数 n,mn,m,分别表示螺旋矩阵的行数和列数。
第二行包含两个整数 r,cr,c,表示要求的行号和列号。
其中,2≤n,m≤1000,1≤r≤n,1≤c≤m2≤n,m≤1000,1≤r≤n,1≤c≤m。
输出描述
输出一个整数,表示螺旋矩阵中第 rr 行第 cc 列的元素的值。
输入输出样例
示例
输入
4 5
2 2
输出
15
运行限制
- 最大运行时间:1s
- 最大运行内存: 256M
总通过次数: 4341 | 总提交次数: 4676 | 通过率: 92.8%
难度: 困难 标签: 2020, 模拟, 暴力, 省模拟赛
螺旋矩阵生成算法与C++实现
我将从算法思路、代码实现、实例验证、优化建议等方面全面解析螺旋矩阵问题。通过边界控制法(模拟法)实现螺旋矩阵的生成,以下是详细解决方案:
🌟 算法思路:边界控制法
- 初始化边界:定义上(top)、下(bottom)、左(left)、右(right)四个边界
- 顺时针填充:
- 左→右填充上边界(top行)
- 上→下填充右边界(right列)
- 右→左填充下边界(bottom行)
- 下→上填充左边界(left列)
- 边界收缩:每完成一条边,收缩对应边界
- 终止条件:填充完所有元素(n×m个)
⚙️ C++代码实现
#include <iostream>
#include <vector>
using namespace std;int main() {int n, m, r, c;cin >> n >> m >> r >> c;vector<vector<int>> matrix(n, vector<int>(m, 0));int top = 0, bottom = n - 1, left = 0, right = m - 1;int count = 1, total = n * m;while (count <= total) {// 左→右填充上边界for (int i = left; i <= right && count <= total; i++) {matrix[top][i] = count++;}top++;// 上→下填充右边界for (int i = top; i <= bottom && count <= total; i++) {matrix[i][right] = count++;}right--;// 右→左填充下边界for (int i = right; i >= left && count <= total; i--) {matrix[bottom][i] = count++;}bottom--;// 下→上填充左边界for (int i = bottom; i >= top && count <= total; i--) {matrix[i][left] = count++;}left++;}cout << matrix[r - 1][c - 1];return 0;
}
🔍 代码解析
- 边界初始化:
top=0, bottom=n-1
定义垂直边界left=0, right=m-1
定义水平边界
- 循环控制:
count
记录当前填充数字total=n*m
为终止条件
- 方向处理:
- 每个
for
循环处理一个方向 - 循环条件确保边界有效且未填满
- 每个
- 边界更新:
- 每个方向完成后收缩对应边界
- 如填充上边界后
top++
🧪 实例验证(4×5矩阵)
1 2 3 4 5
14 15 16 17 6
13 20 19 18 7
12 11 10 9 8
- 查询(2,2):第2行第2列 → 15(正确)
- 执行流程:
- 填充第0行:1-5
- 填充最右列:6-8
- 填充最下行:9-12
- 填充最左列:13-14
- 填充内层:15-20
⚠️ 注意事项
- 边界检查:每个方向循环需同时检查
count <= total
- 矩形处理:非正方形时需注意最后可能剩余一行/一列
- 索引转换:输出时行列索引需-1(从0开始)
- 内存优化:当n,m较大时可用一维数组模拟
🔧 测试用例设计
测试类型 | 输入(n,m,r,c) | 预期输出 | 验证点 |
---|---|---|---|
最小矩阵 | 2,2,1,1 | 1 | 起始位置 |
最大边界 | 1000,1000,1000,1000 | 1000000 | 性能与边界 |
单行矩阵 | 1,5,1,3 | 3 | 行边界处理 |
单列矩阵 | 5,1,3,1 | 3 | 列边界处理 |
中心位置 | 5,5,3,3 | 21 | 内层计算 |
矩形矩阵 | 3,4,2,3 | 10 | 非正方形处理 |
🚀 优化建议
- 直接计算法:对于超大矩阵(n,m>10⁴),使用数学公式直接计算目标位置值
int layer = min(min(r-1, n-r), min(c-1, m-c)); int outer = 2*(n+m-2)*layer - 4*(layer-1)*layer; // 再计算目标点在内层的位置
- 方向向量优化:使用
dx[4], dy[4]
方向数组简化代码 - 状态机实现:通过状态转移减少边界判断次数
- 分治策略:将矩阵分为四象限递归处理
对于n,m ≤ 1000的规模,边界控制法在时间(1s内)和空间(4MB)上完全满足要求。实际提交通过率92.8%,验证了算法的可靠性
1
2
4
。
💡 扩展思考
- 如何生成逆时针螺旋矩阵?
- 调整填充顺序:上→右→下→左
- 如何实现蛇形矩阵?
- 添加方向标志位,交替填充方向
- 超大矩阵查询优化?
- 使用数学公式直接计算目标值,避免构建矩阵