P1205 [USACO1.2] 方块转换 Transformations

P1205 [USACO1.2] 方块转换 Transformations

题目描述

一块 n × n n \times n n×n 正方形的黑白瓦片的图案要被转换成新的正方形图案。写一个程序来找出将原始图案按照以下列转换方法转换成新图案的最小方式:

  • 转 90 ° 90\degree 90°:图案按顺时针转 90 ° 90\degree 90°。

  • 转 180 ° 180\degree 180°:图案按顺时针转 180 ° 180\degree 180°。

  • 转 270 ° 270\degree 270°:图案按顺时针转 270 ° 270\degree 270°。

  • 反射:图案在水平方向翻转(以中央铅垂线为中心形成原图案的镜像)。

  • 组合:图案在水平方向翻转,然后再按照 1 ∼ 3 1 \sim 3 1∼3 之间的一种再次转换。

  • 不改变:原图案不改变。

  • 无效转换:无法用以上方法得到新图案。

如果有多种可用的转换方法,请选择序号最小的那个。

只使用上述 7 7 7 个中的一个步骤来完成这次转换。

输入格式

第一行一个正整数 n n n。

然后 n n n 行,每行 n n n 个字符,全部为 @-,表示初始的正方形。

接下来 n n n 行,每行 n n n 个字符,全部为 @-,表示最终的正方形。

输出格式

单独的一行包括 1 ∼ 7 1 \sim 7 1∼7 之间的一个数字(在上文已描述)表明需要将转换前的正方形变为转换后的正方形的转换方法。

输入输出样例 #1

输入 #1

cpp 复制代码
3
@-@
---
@@-
@-@
@--
--@

输出 #1

cpp 复制代码
1

说明/提示

【数据范围】

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 10 1\le n \le 10 1≤n≤10。

USACO Training Section 1.2

提交链接

Transformations

思路分析

📦 数据结构与变量说明

变量名 含义
s[19][19] 原始图案
t[19][19] 目标图案
temp[19][19] 存储变换后的图案用于比较

🔍 函数说明与实现解析


🔹 bool check(a, b)

  • 功能: 判断两个图案是否一模一样

🔹 bool change1(s) ------ 顺时针旋转 90°

  • 变换公式: temp[i][j] = s[n - 1 - j][i]

🔹 bool change2(s) ------ 顺时针旋转 180°

  • 变换公式: temp[i][j] = s[n - 1 - i][n - 1 - j]

🔹 bool change3(s) ------ 顺时针旋转 270°

  • 变换公式: temp[i][j] = s[j][n - 1 - i]

🔹 bool change4(s) ------ 水平反射

  • 变换公式: temp[i][j] = s[i][n - 1 - j]

🔹 组合变换(反射 + 旋转)

cpp 复制代码
char reflected[19][19];
for (int i = 0; i < n; i++)
    for (int j = 0; j < n; j++)
        reflected[i][j] = s[i][n - 1 - j];  // 先水平反射
        
然后尝试对反射后的图案再进行 90/180/270 度旋转,检查是否等于目标图。

🧩 主程序逻辑(流程图)

cpp 复制代码
读取 n 和两个图案 s、t
↓
尝试 change1(旋转 90°)→ 是 → 输出 1
↓
尝试 change2(旋转 180°)→ 是 → 输出 2
↓
尝试 change3(旋转 270°)→ 是 → 输出 3
↓
尝试 change4(反射)→ 是 → 输出 4
↓
尝试 反射+旋转组合 → 是 → 输出 5
↓
s 和 t 完全一致 → 是 → 输出 6
↓
否则 → 输出 7(无法变换)

完整代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;

char s[19][19], t[19][19], temp[19][19];
int n;

bool check(char temp[][19], char t[][19]) // 判断两个 n * n 的图形是否一样
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            if (temp[i][j] != t[i][j])
                return false;
    return true;
}
bool change1(char s[][19]) /*翻转90度*/
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            temp[i][j] = s[n - 1 - j][i];

    return check(temp, t);
}
bool change2(char s[][19]) /*翻转180度*/
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            temp[i][j] = s[n - 1 - i][n - 1 - j];

    return check(temp, t);
}
bool change3(char s[][19]) /*翻转270度*/
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            temp[i][j] = s[j][n - 1 - i];
    return check(temp, t);
}
bool change4(char s[][19]) /*反射*/
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            temp[i][j] = s[i][n - 1 - j];
    return check(temp, t);
}

int main()
{
    cin >> n;
    for (int i = 0; i < n; i++) /*转换前*/
        cin >> s[i];

    for (int i = 0; i < n; i++) /*转换后*/
        cin >> t[i];

    if (change1(s)) // s 翻转 90 度后,看是否和 t 相等
    {
        cout << 1;
    }
    else if (change2(s)) // s 翻转 180 度后,看是否和 t 相等
    {
        cout << 2;
    }
    else if (change3(s)) // // s 翻转 270 度后,看是否和 t 相等
    {
        cout << 3;
    }
    else if (change4(s)) // 反射
    {
        cout << 4;
    }
    else // 组合
    {
        char reflected[19][19];
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < n; ++j)
                reflected[i][j] = s[i][n - 1 - j];
        if (change1(reflected) || change2(reflected) || change3(reflected))
        {
            cout << 5;
        }
        else if (check(s, t))
        {
            cout << 6;
        }
        else
        {
            cout << 7;
        }
    }
    return 0;
}

官方思路

  • 数据结构
    用一个 Board 结构体保存图案内容;直接按值传递,可方便地返回新图案。
  • 三个基本操作
    • rotate:返回顺时针旋转 90° 后的棋盘
    • reflect:返回水平翻转后的棋盘
    • eqboard:判断两棋盘是否完全一致
  • 枚举判断顺序
    按 1→2→3→4→5→6→7 的顺序逐一比较,首次匹配即输出对应编号。

3️⃣ 代码逐行详解

cpp 复制代码
int n;              

struct Board {      
    char b[10][10];  
};

/* ---------- 旋转 90° ---------- */
Board rotate(Board x) {
    Board temp;
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            temp.b[i][j] = x.b[n - 1 - j][i];
    return temp;
}

/* ---------- 水平翻转 ---------- */
Board reflect(Board x) {
    Board temp;
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            temp.b[i][j] = x.b[i][n - 1 - j];
    return temp;
}

/* ---------- 判断两图是否相等 ---------- */
bool eqboard(Board x, Board y) {
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            if (x.b[i][j] != y.b[i][j])
                return false;
    return true;
}
cpp 复制代码
int main() 
{
    Board st, ed;
    cin >> n;

    /* 读入起始图案 */
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            cin >> st.b[i][j];

    /* 读入目标图案 */
    for (int i = 0; i < n; ++i)
        for (int j = 0; j < n; ++j)
            cin >> ed.b[i][j];

    /* ---------- 按优先级逐一比较 ---------- */
    if (eqboard(ed, rotate(st)))                     cout << 1;
    else if (eqboard(ed, rotate(rotate(st))))        cout << 2;
    else if (eqboard(ed, rotate(rotate(rotate(st)))))cout << 3;
    else if (eqboard(ed, reflect(st)))               cout << 4;
    else if (eqboard(ed, rotate(reflect(st))) ||
             eqboard(ed, rotate(rotate(reflect(st)))) ||
             eqboard(ed, rotate(rotate(rotate(reflect(st)))))) cout << 5;
    else if (eqboard(ed, st))                        cout << 6;
    else                                             cout << 7;
    return 0;
}

判断逻辑说明:

  1. 编号 1 ∼ 3 1 \sim 3 1∼3:直接对 s t st st 连续调用 r o t a t e rotate rotate,分别比较 90 ° / 180 ° / 270 ° 90°/180°/270° 90°/180°/270°

  2. 编号 4 4 4:比较一次 r e f l e c t reflect reflect

  3. 编号 5 5 5: r e f l e c t reflect reflect 后再尝试三种旋转

  4. 写成三次 O R OR OR 判断最直观,也可使用循环减少代码

  5. 编号 6 6 6:若原图与目标图完全一致

  6. 编号 7 7 7:上述均不满足则输出 7 7 7

完整代码

cpp 复制代码
#include <bits/stdc++.h>
using namespace std;
int n;

struct Board
{
    char b[10][10];
};

Board rotate(Board x) // 旋转90度
{
    Board temp;

    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            temp.b[i][j] = x.b[n - 1 - j][i];
    return temp;
}
Board reflect(Board x) // 水平旋转
{
    Board temp;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            temp.b[i][j] = x.b[i][n - 1 - j];
    return temp;
}
bool eqboard(Board x, Board y)
{
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            if (x.b[i][j] != y.b[i][j])
                return false;
    return true;
}
int main()
{
    Board st, ed;
    cin >> n;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            cin >> st.b[i][j];

    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++)
            cin >> ed.b[i][j];

    if (eqboard(ed, rotate(st)))
    {
        cout << 1;
    }
    else if (eqboard(ed, rotate(rotate(st))))
    {
        cout << 2;
    }
    else if (eqboard(ed, rotate(rotate(rotate(st)))))
    {
        cout << 3;
    }
    else if (eqboard(ed, reflect(st)))
    {
        cout << 4;
    }
    else if (eqboard(ed, rotate(reflect(st))) || eqboard(ed, rotate(rotate(reflect(st)))) || eqboard(ed, rotate(rotate(rotate(reflect(st))))))
    {
        cout << 5;
    }
    else if (eqboard(ed, st))
    {
        cout << 6;
    }
    else
    {
        cout << 7;
    }
    return 0;
}
相关推荐
AICodeThunder3 分钟前
图论(1):多叉树
算法·深度优先·图论
Gary董20 分钟前
红黑树、B树、B+树
数据结构·b树
努力写代码的熊大1 小时前
设计循环队列oj题(力口622)
算法
qq_366336371 小时前
JUC并发包CountDownLatch减法计数器的使用实例(多线程)
java·开发语言·算法
屁股割了还要学1 小时前
【C语言进阶】题目练习(3)
c语言·开发语言·c++·学习·算法·青少年编程
mit6.8242 小时前
7.19 换根dp | vpp |滑窗
c++·算法
一只小蒟蒻2 小时前
马走日题解
算法·深度优先
weisian1512 小时前
力扣经典算法篇-26-长度最小的子数组(暴力求解法,左右指针法)
数据结构·算法·leetcode
花落yu2 小时前
动态规划——数位DP经典题目
算法·动态规划
西猫雷婶3 小时前
python学智能算法(十九)|SVM基础概念-超平面
开发语言·人工智能·python·深度学习·算法·机器学习·支持向量机