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
提交链接
思路分析
📦 数据结构与变量说明
变量名 | 含义 |
---|---|
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 ∼ 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°
-
编号 4 4 4:比较一次 r e f l e c t reflect reflect
-
编号 5 5 5: r e f l e c t reflect reflect 后再尝试三种旋转
-
写成三次 O R OR OR 判断最直观,也可使用循环减少代码
-
编号 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;
}