UVa 281 Rubik‘s Cube
2026/5/16 15:19:10 网站建设 项目流程

题目分析

魔方是一个3×3×33 \times 3 \times 33×3×3的立方体,共有666个面,每个面有999个贴纸,总计545454个贴纸。每个贴纸有一种颜色,颜色用字母表示(A-Za-z)。两个魔方被认为相同,当且仅当可以通过以下两种操作的任意组合使两者完全相同:

  1. 整体旋转:将整个魔方绕通过相对面中心的轴旋转90∘90^\circ90的整数倍。由于魔方有333个这样的轴,每个轴有444个方向,但部分旋转会产生重复结果,实际上共有242424种不同的朝向。
  2. 颜色重标号:将某种颜色的所有贴纸重新涂成当前魔方上不存在的另一种颜色(相当于建立颜色之间的双射映射)。

解题思路

核心挑战

  1. 输入格式复杂:每个魔方以999494949列的展开图形式给出,中间用|分隔,且字符之间有空格。
  2. 颜色可重标号:不能直接比较颜色字母,需要寻找颜色之间的映射关系。
  3. 242424种朝向:需要枚举所有可能的旋转状态。

解决策略

第一步:输入解析

输入每行包含空格和|分隔符。处理方式:

  • 去除每行中的空格和|,得到连续的242424个字符(左右魔方各121212个字符)。
  • 121212个字符属于第一个魔方,后121212个字符属于第二个魔方。
第二步:建立贴纸索引映射

魔方展开图(999×\times×121212列)中,每个位置对应魔方上的一个贴纸。需要预先定义netToIdx[9][12]数组,将输入位置映射到545454个贴纸的线性索引。索引分配方式:

  • 0∼80 \sim 808:上面(U
  • 9∼179 \sim 17917:前面(F
  • 18∼2618 \sim 261826:左面(L
  • 27∼3527 \sim 352735:右面(R
  • 36∼4436 \sim 443644:后面(B
  • 45∼5345 \sim 534553:下面(D

每个面内部的999个贴纸按行优先顺序排列(左上角为000,右下角为888)。

第三步:预处理242424种旋转

通过手工制作纸模型或数学推导,得到242424种旋转下666个面的置换关系以及每个面的朝向变化。每个旋转用长度为666的数组表示,数组元素为两位数:

  • 个位数:该位置对应的原始面索引(0∼50 \sim 505
  • 十位数:该面需要逆时针旋转90∘90^\circ90的次数(0∼30 \sim 303

例如,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),非常高效。

代码实现要点

  1. 旋转操作:用3×33 \times 33×3数组表示每个面,rotate函数实现逆时针90∘90^\circ90旋转。
  2. 映射检查:使用std::map\texttt{std::map}std::map存储颜色映射关系,同时检查双向一致性。
  3. 空行处理:每组数据之间有一个空行,需要在读入时跳过。

完整代码

// 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;}

总结

本题的核心在于:

  1. 理解魔方旋转的数学本质——只有242424种不同的朝向。
  2. 正确解析输入——去除空格和分隔符,建立贴纸索引映射。
  3. 颜色重标号的判断——通过建立双射映射来比较两个魔方。

通过预处理242424种旋转的面对应关系,可以高效地枚举所有可能的朝向,结合颜色映射检查,最终判断两个魔方是否相同。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询