题解:学而思编程 回形矩阵
【题目来源】
学而思编程:回形矩阵
【题目描述】
给定一个 \(n\) 行 \(m\) 列的二维数组,要求从二维数组的左上角位置开始,沿顺时针或逆时针方向将数字 \(1\) 到 \(n * m\) 按照回形从外向内依次填入数组中。
【输入】
第一行两个整数 \(n\),\(m\);
第二行一个字符 \(d\),其中'1'表示顺时针方向,'0'表示逆时针方向。
【输出】
输出一个 \(n\times m\) 的二维数组,表示从二维数组的左上角位置开始,沿 \(d\) 方向将数字 \(1\) 到 \(n * m\) 填入数组之后的结果。
【输入样例】
3 3
1
【输出样例】
1 2 3
8 9 4
7 6 5
【核心思想】
-
问题分析:给定 \(n\) 行 \(m\) 列的矩阵,从左上角开始,按顺时针或逆时针方向以回形(螺旋)方式填入 \(1\) 到 \(n \times m\)。这是一个方向模拟问题,关键在于维护当前位置和方向,在边界或已填位置处自动转向。
-
算法选择:
- 方向数组:用
dx[4]和dy[4]定义四个基本方向(右、下、左、上) - 碰壁转向:每次尝试沿当前方向前进,若越界或目标位置已填,则按顺时针或逆时针规则转向
- 转向参数:用
p = 1(顺时针)或p = -1(逆时针)控制方向索引的变化
- 方向数组:用
-
关键步骤:
- 初始化:
- 读取 \(n\)(行数)、\(m\)(列数)、\(d\)(方向标志,
1顺时针,0逆时针) - 矩阵
g[1..n][1..m]全局定义,自动初始化为 \(0\) - 设置起始位置 \((x, y) = (1, 1)\)
- 若 \(d = 1\):
dir = 0(初始向右),p = 1(顺时针转向:右→下→左→上) - 若 \(d = 0\):
dir = 1(初始向下),`p = -1$(逆时针转向:下→右→上→左)
- 读取 \(n\)(行数)、\(m\)(列数)、\(d\)(方向标志,
- 螺旋填数(遍历 \(i\) 从 \(1\) 到 \(n \times m\)):
g[x][y] = i:在当前位置填入数字- 计算下一步坐标:\(a = x + dx[dir]\),\(b = y + dy[dir]\)
- 若越界(\(a < 1\) 或 \(a > n\) 或 \(b < 1\) 或 \(b > m\))或已填(
g[a][b] \neq 0):dir = (dir + p + 4) \bmod 4:按规则转向(加 \(4\) 保证非负)- 重新计算 \(a, b\)
x = a, y = b:移动到新位置
- 输出矩阵:按行输出
g[1..n][1..m]
- 初始化:
-
时间/空间复杂度:
- 时间复杂度:\(O(n \times m)\),每个位置恰好填入一次
- 空间复杂度:\(O(n \times m)\),存储矩阵
-
方向模拟的核心思想:
- 方向编码:四个方向用索引 \(0, 1, 2, 3\) 编码,方向数组实现坐标变化的统一处理,避免大量
if-else - 碰壁检测:不预计算边界,而是"走一步看一步",通过越界检查和已填标记自动触发转向,代码简洁且鲁棒
- 转向统一化:顺时针
dir = (dir + 1) \bmod 4,逆时针dir = (dir - 1 + 4) \bmod 4,用参数p统一为(dir + p + 4) \bmod 4 - 初始方向差异化:顺时针从向右开始(符合阅读习惯),逆时针从向下开始,通过
dir初值区分 - 适用于"矩阵螺旋遍历/填充"类问题,方向数组 + 碰壁转向是经典模板,可扩展至多层螺旋、蛇形填充等变种
- 方向编码:四个方向用索引 \(0, 1, 2, 3\) 编码,方向数组实现坐标变化的统一处理,避免大量
【算法标签】
模拟
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int dx[4] = {0, 1, 0, -1}; // 方向数组:右、下、左、上
int dy[4] = {1, 0, -1, 0};
/*
顺时针:右->下->左->上->右...
逆时针:下->右->上->左->下...
*/
int g[N][N]; // 存储矩阵
int n, m, d; // 行数、列数、方向标志
int main()
{
cin >> n >> m >> d; // 输入n行m列,方向d
int x = 1, y = 1, dir, p; // 当前位置(1,1),方向,转向参数
// 根据d初始化方向
if (d == 1) // 顺时针
{
dir = 0; // 初始向右
p = 1; // 顺时针旋转:+1
}
else // 逆时针
{
dir = 1; // 初始向下
p = -1; // 逆时针旋转:-1
}
// 填数1到n*m
for (int i = 1; i <= n * m; i++)
{
g[x][y] = i; // 填写数字
// 尝试沿着当前方向前进
int a = x + dx[dir], b = y + dy[dir];
// 如果越界或已经填过,需要转向
if (a < 1 || a > n || b < 1 || b > m || g[a][b] != 0)
{
// 转向:(dir + p + 4) % 4
dir = (dir + p + 4) % 4;
a = x + dx[dir], b = y + dy[dir];
}
x = a, y = b; // 移动到下一个位置
}
// 输出矩阵
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
cout << g[i][j] << " ";
}
cout << endl;
}
return 0;
}
【运行结果】
3 3
1
1 2 3
8 9 4
7 6 5
浙公网安备 33010602011771号