题目分析
魔方是一个3×3×33 \times 3 \times 33×3×3的立方体,共有666个面,每个面有999个贴纸,总计545454个贴纸。每个贴纸有一种颜色,颜色用字母表示(A-Z或a-z)。两个魔方被认为相同,当且仅当可以通过以下两种操作的任意组合使两者完全相同:
- 整体旋转:将整个魔方绕通过相对面中心的轴旋转90∘90^\circ90∘的整数倍。由于魔方有333个这样的轴,每个轴有444个方向,但部分旋转会产生重复结果,实际上共有242424种不同的朝向。
- 颜色重标号:将某种颜色的所有贴纸重新涂成当前魔方上不存在的另一种颜色(相当于建立颜色之间的双射映射)。
解题思路
核心挑战
- 输入格式复杂:每个魔方以999行494949列的展开图形式给出,中间用
|分隔,且字符之间有空格。 - 颜色可重标号:不能直接比较颜色字母,需要寻找颜色之间的映射关系。
- 242424种朝向:需要枚举所有可能的旋转状态。
解决策略
第一步:输入解析
输入每行包含空格和|分隔符。处理方式:
- 去除每行中的空格和
|,得到连续的242424个字符(左右魔方各121212个字符)。 - 前121212个字符属于第一个魔方,后121212个字符属于第二个魔方。
第二步:建立贴纸索引映射
魔方展开图(999行×\times×121212列)中,每个位置对应魔方上的一个贴纸。需要预先定义netToIdx[9][12]数组,将输入位置映射到545454个贴纸的线性索引。索引分配方式:
- 0∼80 \sim 80∼8:上面(
U) - 9∼179 \sim 179∼17:前面(
F) - 18∼2618 \sim 2618∼26:左面(
L) - 27∼3527 \sim 3527∼35:右面(
R) - 36∼4436 \sim 4436∼44:后面(
B) - 45∼5345 \sim 5345∼53:下面(
D)
每个面内部的999个贴纸按行优先顺序排列(左上角为000,右下角为888)。
第三步:预处理242424种旋转
通过手工制作纸模型或数学推导,得到242424种旋转下666个面的置换关系以及每个面的朝向变化。每个旋转用长度为666的数组表示,数组元素为两位数:
- 个位数:该位置对应的原始面索引(0∼50 \sim 50∼5)
- 十位数:该面需要逆时针旋转90∘90^\circ90∘的次数(0∼30 \sim 30∼3)
例如,faces[i][j] = 12表示:旋转iii后的第jjj个面,来自原始的第222个面,并且需要逆时针旋转111次。
第四步:颜色重标号匹配
对于第一个魔方的每种朝向(242424种),与第二个魔方的原始朝向进行比较:
- 遍历545454个位置(666个面×\times×999个贴纸)
- 建立从第一个魔方颜色到第二个魔方颜色的映射
- 如果映射过程中出现冲突(同一个源颜色映射到不同目标颜色,或不同源颜色映射到同一个目标颜色),则该朝向不匹配
- 如果242424种朝向中有任意一种匹配成功,则两个魔方相同
第五步:复杂度分析
- 最多处理nnn对魔方,nnn由输入给定。
- 每对魔方枚举242424种旋转,每种旋转检查545454个贴纸。
- 总时间复杂度:O(n×24×54)=O(n)O(n \times 24 \times 54) = O(n)O(n×24×54)=O(n),非常高效。
代码实现要点
- 旋转操作:用3×33 \times 33×3数组表示每个面,
rotate函数实现逆时针90∘90^\circ90∘旋转。 - 映射检查:使用std::map\texttt{std::map}std::map存储颜色映射关系,同时检查双向一致性。
- 空行处理:每组数据之间有一个空行,需要在读入时跳过。
完整代码
// Rubik's Cube// UVa ID: 281// Verdict: Accepted// Submission Date: 2026-05-16// UVa Run Time: 0.010s//// 版权所有(C)2026,邱秋。metaphysis # yeah dot net#include<bits/stdc++.h>usingnamespacestd;// 输入 9x12(去除空格后)到 54 个贴纸的映射intnetToIdx[9][12]={{-1,-1,-1,0,1,2,-1,-1,-1,-1,-1,-1},{-1,-1,-1,3,4,5,-1,-1,-1,-1,-1,-1},{-1,-1,-1,6,7,8,-1,-1,-1,-1,-1,-1},{18,19,20,9,10,11,27,28,29,36,37,38},{21,22,23,12,13,14,30,31,32,39,40,41},{24,25,26,15,16,17,33,34,35,42,43,44},{-1,-1,-1,45,46,47,-1,-1,-1,-1,-1,-1},{-1,-1,-1,48,49,50,-1,-1,-1,-1,-1,-1},{-1,-1,-1,51,52,53,-1,-1,-1,-1,-1,-1}};// 24 种面对置换及旋转(6个面:U, F, L, R, B, D 对应索引 0 - 5)// 个位数表示所对应的原始面,十位数表示该面在变换过程中需要向左旋转的次数intfaces[24][6]={{0,1,2,3,4,5},{10,2,4,1,3,35},{20,4,3,2,1,25},{30,3,1,4,2,15},{1,5,12,33,20,24},{11,12,20,5,33,14},{21,20,33,12,5,4},{31,33,5,20,12,34},{2,35,14,31,30,23},{12,14,30,35,31,13},{22,30,31,14,35,3},{32,31,35,30,14,33},{3,15,11,34,10,22},{13,11,10,15,34,12},{23,10,34,11,15,2},{33,34,15,10,11,32},{4,25,13,32,0,21},{14,13,0,25,32,11},{24,0,32,13,25,1},{34,32,25,0,13,31},{5,24,22,23,21,0},{15,22,21,24,23,30},{25,21,23,22,24,20},{35,23,24,21,22,10}};// 逆时针旋转 90 度voidrotate(charcube[3][3]){charrotated[3][3];for(inti=0;i<3;i++)for(intj=0;j<3;j++)rotated[3-j-1][i]=cube[i][j];memcpy(cube,rotated,sizeofrotated);}intmain(){intn;cin>>n;cin.ignore();while(n--){// 读取输入string line;vector<string>cube1,cube2;for(inti=0;i<9;++i){getline(cin,line);string clean;for(inti=0;i<line.length();i++){if(line[i]==' '||line[i]=='|')continue;clean+=line[i];}cube1.push_back(clean.substr(0,12));cube2.push_back(clean.substr(12));}// 获取各个面charcolor1[6][3][3],color2[6][3][3];for(inti=0;i<9;i++)for(intj=0;j<12;j++){intid=netToIdx[i][j];if(netToIdx[i][j]!=-1){color1[id/9][(id%9)/3][(id%9)%3]=cube1[i][j];color2[id/9][(id%9)/3][(id%9)%3]=cube2[i][j];}}boolsame=false;charcolor3[6][3][3];for(inti=0;i<24&&!same;i++){// 获取旋转后的各个面for(intj=0;j<6;j++){introtates=faces[i][j]/10,face=faces[i][j]%10;for(intr=0;r<3;r++)for(intc=0;c<3;c++)color3[j][r][c]=color1[face][r][c];for(intk=0;k<rotates;k++)rotate(color3[j]);}// 与目标魔方尝试建立映射boolmatched=true;map<char,char>mp;for(intj=0;j<6&&matched;j++)for(intr=0;r<3&&matched;r++)for(intc=0;c<3;c++){if(!mp.count(color3[j][r][c]))mp[color3[j][r][c]]=color2[j][r][c];else{if(mp[color3[j][r][c]]!=color2[j][r][c]){matched=false;break;}}}if(matched)same=true;}cout<<(same?"same":"different")<<'\n';// 读取空行getline(cin,line);}return0;}总结
本题的核心在于:
- 理解魔方旋转的数学本质——只有242424种不同的朝向。
- 正确解析输入——去除空格和分隔符,建立贴纸索引映射。
- 颜色重标号的判断——通过建立双射映射来比较两个魔方。
通过预处理242424种旋转的面对应关系,可以高效地枚举所有可能的朝向,结合颜色映射检查,最终判断两个魔方是否相同。