习题4-4 UVA253 Cube painting(29行AC代码)

紫书刷题进行中,题解系列点这里

习题4-4 UVA253 Cube painting(29行AC代码)

题目大意

现有固定编号(1~6)的立方体,给定两个上色序列A,B(仅由红蓝绿三种颜色构成),问A能否通过x,y,z三个旋转轴旋转得到B(不考虑镜像,即轴对称)

思路分析

有很多人通过两个正方体的3组对立面是否一致来判断结果,其实有bug,可如下构造反例

  • 构造A:rbg各出现两次,且对立面均不同色
  • 构造B:选择一个对立面交换颜色
grbrgbggbrrb // false, 仅判断3组对立面相等的反例

因此,可通过暴力枚举,解决问题,但还需多一些思考和推导,可得到结论1:

结论1:若正方体A,B上色方案相同,那么A必定可在3次旋转得到B

  • 旋转轴共3个(x,y,z),每个轴共有4个旋转角度(0,90,180,270)

可将三个旋转轴看成空间基向量,任意的向量均可由基向量构造出来,其中旋转角度就是基向量前的常数

结论2:B=d1*x+d2*y+d3*z // 类似这种表达,(d1,d2,d3)表示绕每个轴旋转角度

根据结论1可知,旋转组合顺序与结果无关,4*4*4=64种情况必定包含了所有的旋转结果,因此,对于每个判断,仅需枚举64种旋转即可。

算法设计

对于旋转,可用一个轮换来模拟(类似约瑟夫环过程),以下分别表示绕3个轴转动时会轮换改变的序列

int a[3][4] = {{2,4,5,3}, {2,6,5,1}, {1,4,6,3}}; // 3个旋转轴对应改变的轮换序列

用string存储上色序列,定义旋转函数rotate,表示正方体绕i轴旋转j*90度。

void rotate(string& sr, int i, int j) { // sr绕i轴旋转j*90度
    string s = sr;
    for (int k = 0; k <= 3; k ++) { // 轮换:模拟旋转
        sr[a[i][k]-1] = s[a[i][(j+k)%4]-1]; // 从0开始存储,正方体标号从1开始
    }
}

测试用例设计

rbgggrrggbgr // True, 1轴旋转
rrrbbbrrbbbr // false
rbgrbgrrrrrg // false
rbgggrrgggbr // true,全等2
rggbgrrgggbr // true,
gggggggggggg // true,全等1
rggbgrggrrgb // True,2轴旋转
rggbgrggrrbg // True,3轴旋转
ggrrgbggrrbg // True, 1轴旋转
rbgggrgrbgrg // True, 3轴4次旋转
rbgggrgbrrgg // True, 3轴4次旋转
grbrgbggbrrb // false, 仅判断3组对立面相等的反例

AC代码(C++11,判定条件,中级模拟,推导思考,轮换)

#include<bits/stdc++.h>
using namespace std;
int a[3][4] = {{2,4,5,3}, {2,6,5,1}, {1,4,6,3}}; // 3个旋转轴对应改变的轮换序列
string sa, sb, st;
void rotate(string& sr, int i, int j) { // sr绕i轴旋转j*90度
    string s = sr;
    for (int k = 0; k <= 3; k ++) { // 轮换:模拟旋转
        sr[a[i][k]-1] = s[a[i][(j+k)%4]-1]; // 从0开始存储,正方体标号从1开始
    }
}
int main() {
    while (cin >>st) {
        sa = st.substr(0,6); sb = st.substr(6);
        bool isSame = false; // 判断是否存在一样的情况
        for (int i = 0; i < 4 && !isSame; i ++) { // x轴4种转动角度
            for (int j = 0; j < 4 && !isSame; j ++) { // y轴
                for (int k = 0; k < 4 && !isSame; k ++) { // z轴
                    st = sb; // 更新
                    rotate(st, 0, i); // x轴转i*90角度
                    rotate(st, 1, j); // y轴转j*90角度
                    rotate(st, 2, k); // z轴转k*90角度
                    if (st == sa) isSame = true;
                }
            }
        }
        printf("%s\n", isSame ? "TRUE" : "FALSE");
    }
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值