实现矩阵顺时针旋转和水平反射,按题目编号顺序逐一比较目标图案。
OJ: luogu
题目 ID: P1205
难度:普及-
标签:模拟矩阵字符串python
创建: 2026-07-15 18:58
更新: 2026-10-07 12:15
前置题目
noi_openjudge ch0108-12变幻的矩阵B 复用 A 教的「把各矩阵变换按下标构造出来、再按题目优先级逐个比较判定」这一步,只是把三种变换扩成旋转 90/180/270、水平反射及其复合共七种情况。noi_openjudge ch0108-11图像旋转B 的 rotate 函数复用 A 的「顺时针旋转 90 度 = 结果每行取原图一列、从下到上读取」这一步,并用它组合出 90/180/270 与反射后再旋转,再叠加 A 未教的水平反射与按编号顺序枚举取最小答案。roj 1127图像旋转B 的 rotate 函数直接复用 A 教的顺时针 90° 坐标映射(main.cpp 中 dst[j][n-1-i]=src[i][j] 与 A 的 b[i][j]=a[n-1-j][i] 等价)来生成旋转矩阵,只是再叠加水平反射与 7 种情况的枚举比较。
题意
给出变换前后的 n * n 字符方阵,判断它们属于哪一种变换:旋转 90/180/270 度、水平反射、反射后再旋转、不变,或无效。若多种都满足,输出编号最小的。
思路
把矩阵保存为字符串列表。先写两个函数:
rotate(pattern):顺时针旋转90度;reflect(pattern):水平反射,也就是每一行反转。
然后按题目编号顺序比较:
rotate(before)- 旋转两次
- 旋转三次
reflect(before)- 反射后再旋转一次、两次、三次
- 原图不变
- 以上都不是
因为按编号顺序判断,第一种匹配就是最小编号答案。
这题是矩阵变换模拟,正解已经枚举所有题面情况,不创建 brute.py。
Python 知识
/home/rainboy/mycode/hugo-blog/content/program_language/python/oj_input_output_cheatsheet.md:字符矩阵可直接保存为字符串列表。/home/rainboy/mycode/hugo-blog/content/program_language/python/input_output_and_strings.md:字符串切片row[::-1]可以反转一行。rotate中用列表推导式生成旋转后的每一行。- 字符串列表可以直接用
==判断整个矩阵是否相同。
代码
python
def rotate(pattern):
n = len(pattern)
return ["".join(pattern[n - 1 - row][col] for row in range(n)) for col in range(n)]
def reflect(pattern):
return [row[::-1] for row in pattern]
n = int(input())
before = [input().strip() for _ in range(n)]
after = [input().strip() for _ in range(n)]
rot90 = rotate(before)
rot180 = rotate(rot90)
rot270 = rotate(rot180)
reflected = reflect(before)
if rot90 == after:
print(1)
elif rot180 == after:
print(2)
elif rot270 == after:
print(3)
elif reflected == after:
print(4)
elif rotate(reflected) == after or rotate(rotate(reflected)) == after or rotate(rotate(rotate(reflected))) == after:
print(5)
elif before == after:
print(6)
else:
print(7)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-27 00:00
* update_at: 2026-07-27 00:00
*/
#include <bits/stdc++.h>
using namespace std;
int n;
char before[12][12]; // 原始矩阵
char after[12][12]; // 目标矩阵
// 顺时针旋转 90 度
void rotate(char src[12][12], char dst[12][12]) {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
dst[j][n - 1 - i] = src[i][j];
}
// 水平反射
void reflect(char src[12][12], char dst[12][12]) {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
dst[i][n - 1 - j] = src[i][j];
}
// 比较两个矩阵是否相等
bool equal(char a[12][12], char b[12][12]) {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
if (a[i][j] != b[i][j]) return false;
return true;
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) cin >> before[i];
for (int i = 0; i < n; i++) cin >> after[i];
char t1[12][12], t2[12][12], t3[12][12], r[12][12];
rotate(before, t1);
rotate(t1, t2);
rotate(t2, t3);
reflect(before, r);
if (equal(t1, after)) cout << 1;
else if (equal(t2, after)) cout << 2;
else if (equal(t3, after)) cout << 3;
else if (equal(r, after)) cout << 4;
else {
// 反射后再旋转 1~3 次
rotate(r, t1);
rotate(t1, t2);
rotate(t2, t3);
if (equal(t1, after) || equal(t2, after) || equal(t3, after))
cout << 5;
else if (equal(before, after)) cout << 6;
else cout << 7;
}
return 0;
}Pythonic 写法
旋转/翻转函数:
python
def rot(p):
n=len(p)
return [''.join(p[n-1-r][c] for r in range(n)) for c in range(n)]
def ref(p):
return [row[::-1] for row in p]
n=int(input())
b=[input().strip() for _ in range(n)]
a=[input().strip() for _ in range(n)]
r1,r2,r3=rot(b),rot(rot(b)),rot(rot(rot(b)))
rf=ref(b)
if r1==a: print(1)
elif r2==a: print(2)
elif r3==a: print(3)
elif rf==a: print(4)
elif any(x==a for x in (rot(rf),rot(rot(rf)),rot(rot(rot(rf))))): print(5)
elif b==a: print(6)
else: print(7)复杂度
每次矩阵变换需要
总结
矩阵变换题先把基础操作写成函数,再按题目编号顺序组合比较。这样既不漏情况,也能自然满足“输出最小编号”的要求。