[USACO1.2] 方块转换 Transformations

GitHub跳转原题关系图返回列表

实现矩阵顺时针旋转和水平反射,按题目编号顺序逐一比较目标图案。

OJ: luogu

题目 ID: P1205

难度:普及-

标签:模拟矩阵字符串python

日期: 2026-07-15 18:58

题意

给出变换前后的 n * n 字符方阵,判断它们属于哪一种变换:旋转 90/180/270 度、水平反射、反射后再旋转、不变,或无效。若多种都满足,输出编号最小的。

思路

把矩阵保存为字符串列表。先写两个函数:

  • rotate(pattern):顺时针旋转 90 度;
  • reflect(pattern):水平反射,也就是每一行反转。

然后按题目编号顺序比较:

  1. rotate(before)
  2. 旋转两次
  3. 旋转三次
  4. reflect(before)
  5. 反射后再旋转一次、两次、三次
  6. 原图不变
  7. 以上都不是

因为按编号顺序判断,第一种匹配就是最小编号答案。

这题是矩阵变换模拟,正解已经枚举所有题面情况,不创建 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)

复杂度

每次矩阵变换需要 O(n2)O(n^2),总共常数次变换,时间复杂度是 O(n2)O(n^2),空间复杂度是 O(n2)O(n^2)

总结

矩阵变换题先把基础操作写成函数,再按题目编号顺序组合比较。这样既不漏情况,也能自然满足“输出最小编号”的要求。