矩阵重塑(其二)
用一维行优先序列保存矩阵,重塑只修改形状,转置时按下标映射重排,查询直接定位线性下标。
OJ: shumeng
题目 ID: CSP202406B
难度:普及-
标签:模拟矩阵下标映射
日期: 2026-07-31 16:21
形式化题目
给定一个初始
- 重塑为
:按行优先顺序重排为新的行列形状; - 转置:交换行和列;
- 查询
:输出该位置的元素。
所有操作都保持元素总数不变,且操作保证合法。
思路
关键区分:重塑不改变行优先线性序列,只改形状;转置才真正改变行优先序列。
朴素做法:直接维护二维矩阵
先看直观实现,直接用二维数组保存矩阵,每次操作都显式地在二维下标间搬运元素。
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-31 16:21
* update_at: 2026-08-17 22:39
*/
// brute.cpp:小数据暴力解,直接维护二维矩阵完成重塑、转置与查询。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
int matrix[MAXN][MAXN]; // 直接保存二维矩阵
int n, m;
// 重塑为 x 行 y 列:先按行优先取出所有元素,再按新形状放回
void reshape(int x, int y) {
int temp[MAXN];
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) temp[count++] = matrix[i][j];
}
count = 0;
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) matrix[i][j] = temp[count++];
}
n = x;
m = y;
}
// 转置:新矩阵的 (j,i) 位置放原矩阵的 (i,j)
void transpose() {
int temp[MAXN]; // 平铺存放转置后的元素
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
temp[j * n + i] = matrix[i][j];
}
}
int count = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) matrix[i][j] = temp[count++];
}
swap(n, m);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int operation_count;
cin >> n >> m >> operation_count;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) cin >> matrix[i][j];
}
while (operation_count--) {
int type, x, y;
cin >> type >> x >> y;
if (type == 1) {
reshape(x, y);
} else if (type == 2) {
transpose();
} else {
cout << matrix[x][y] << '\n';
}
}
return 0;
}主解:一维序列 + 下标映射
用一维数组 value 按行优先顺序保存所有元素,同时维护当前行列数
- 重塑:只修改
,数组不动, 。 - 查询:位置
的线性下标是 ,直接输出。 - 转置:原位置
线性下标 ,转置后变为 ,新线性下标 。扫描一遍数组按新下标重排,并交换 。
由于元素总数不超过
代码
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-31 16:21
* update_at: 2026-08-17 22:39
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
int value[MAXN]; // 行优先保存的矩阵元素
int n, m; // 当前矩阵的行数与列数
// 矩阵转置:原位置 (i,j) 的线性下标 i*m+j,转置后位置 (j,i) 的线性下标 j*n+i
void transpose() {
int temp[MAXN];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
temp[j * n + i] = value[i * m + j];
}
}
for (int i = 0; i < n * m; i++) value[i] = temp[i];
swap(n, m);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int operation_count;
cin >> n >> m >> operation_count;
for (int i = 0; i < n * m; i++) cin >> value[i];
while (operation_count--) {
int type, x, y;
cin >> type >> x >> y;
if (type == 1) {
n = x; // 重塑:只改形状,行优先序列不变
m = y;
} else if (type == 2) {
transpose(); // 转置:需要重排元素并交换行列
} else {
cout << value[x * m + y] << '\n';
}
}
return 0;
}复杂度
设矩阵元素总数为
- 时间:初始读入
;转置 ;重塑与查询 。转置最多 次,总时间复杂度 。 - 空间:一维数组保存全部元素,空间复杂度
。
总结
把“形状变化”和“元素重排”分开处理就不会混淆:重塑只是换一种方式解释同一串数据,转置才需要真正的下标重排。用一维行优先序列配合