5-21 2X2X2魔方问题
问题描述
2×2×22×2×2 魔方的构造如图所示。图中英文字母 U,L,F,R,B,D 分别表示魔方的 6 个 面中的上面,左面,前面,右面,后面,底面。魔方的每个面都可以绕其中轴旋转。给定魔 方的初始状态,可以经过若干次旋转将魔方变换成每个面都只有一种颜色的状态。绕中轴将 一个面旋转 90 度算作一次旋转。试设计一个算法计算出从初始状态到目标状态(每个面都 只有一种颜色的状态)所需的最少旋转次数。

设计一个算法,对于给定的 2×2×22×2×2 魔方的初始状态,计算从初始状态到目标状态(每个面都只有一种颜色的状态)所需的最少旋转次数。
数据输入:
2×2×22×2×2 魔方目标状态的每个面都有一种颜色,分别用大写英文字母 W,O,G,R,Y,B 来表示。将 6 个面展开并编号如下图所示。文件将给定魔 方的初始状态的 6 个面,按照其编号依次排列,共有 12 行,每行有 2 个表示方块颜色的大 写英文字母。

Java
package Chapter5HuiSuFa;
import java.util.Arrays;
import java.util.Scanner;
public class MoFang2x2x2 {
private static class cubeT{
int[] cube = new int[8];
}
private static char[] lcols = {'U','U','U','U','L','L','L','L','F','F','F','F','R','R','R','R','B','B','B','B','D','D','D','D'};
private static final int ID = 0;
private static final int FACE_U_CW = 1;
private static final int FACE_U_CCW = 2;
private static final int FACE_U_180 = 3;
private static final int FACE_L_CW = 4;
private static final int FACE_L_CCW = 5;
private static final int FACE_L_180 = 6;
private static final int FACE_F_CW = 7;
private static final int FACE_F_CCW = 8;
private static final int FACE_F_180 = 9;
private static final int CORNER_0_CW = 10;
private static final int CORNER_0_CCW = 11;
private static final int CORNER_2_CW = 12;
private static final int CORNER_2_CCW = 13;
private static final int CORNER_5_CW = 14;
private static final int CORNER_5_CCW = 15;
private static final int CORNER_7_CW = 16;
private static final int CORNER_7_CCW = 17;
private static final int EDGE_1 = 18;
private static final int EDGE_3 = 19;
private static final int EDGE_4 = 20;
private static final int EDGE_6 = 21;
private static final int EDGE_8 = 22;
private static final int EDGE_9 = 23;
private static int[] lc = {1,2,4,3,1,1,1,5,0,3,2,0,5,4,5,2,4,0,3,2,4,3,0,5};
private static int[] rc = new int[24];
private static int[] fc = new int[24];
private static int[] bc = new int[24];
private static int[] uc = new int[24];
private static int[] dc = new int[24];
private static final int FF = 0;//前面顺时针
private static final int FR = 1;//前面逆时针
private static final int UF = 2;//上面顺时针
private static final int UR = 3;//上面逆时针
private static final int RF = 4;//右面顺时针
private static final int RR = 5;//右面逆时针
private static String[] moveOut = {"F","F-","U","U-","R","R-"};
private static int[][] mult;
private static int[] res;
private static int minmov,maxdepth=100000;
public static void main(String[] args){
Scanner input = new Scanner(System.in);
while (true){
mult = new int[24][24];
res = new int[10000];
cubeT x = new cubeT();
char[] s = new char[24];
String[] str = new String[24];
init();
for(int i=0; i<24; i++)
str[i] = input.next();
for(int i=0; i<24; i++)
System.arraycopy(str[i].toCharArray(),0,s,i,1);
setCube(x,s);
outsol(IDsearch(x,maxdepth));
}
}
private static boolean backtrack(int depth, cubeT p){
cubeT[] newp = new cubeT[6];
boolean result = false;
if(depth == 0){
if(solved(p)){
return true;
}else
return false;
}
for(int i=0; i<6; i++){
newp[i] = new cubeT();
move(p,newp[i],i);
result = backtrack(depth-1,newp[i]);
if(result){
res[depth-1] = i;
return true;
}
}
return false;
}
private static void move(cubeT f, cubeT t, int mv){
int[] cube;
cube = Arrays.copyOf(f.cube, 8);
t.cube = cube;
switch (mv){
case FF:
t.cube[0] = mult[FACE_F_CW][f.cube[2]];
t.cube[1] = mult[FACE_F_CW][f.cube[0]];
t.cube[2] = mult[FACE_F_CW][f.cube[3]];
t.cube[3] = mult[FACE_F_CW][f.cube[1]];
break;
case FR:
t.cube[2] = mult[FACE_F_CCW][f.cube[0]];
t.cube[0] = mult[FACE_F_CCW][f.cube[1]];
t.cube[3] = mult[FACE_F_CCW][f.cube[2]];
t.cube[1] = mult[FACE_F_CCW][f.cube[3]];
break;
case UF:
t.cube[4] = mult[FACE_U_CW][f.cube[0]];
t.cube[5] = mult[FACE_U_CW][f.cube[4]];
t.cube[0] = mult[FACE_U_CW][f.cube[1]];
t.cube[1] = mult[FACE_U_CW][f.cube[5]];
break;
case UR:
t.cube[0] = mult[FACE_U_CCW][f.cube[4]];
t.cube[4] = mult[FACE_U_CCW][f.cube[5]];
t.cube[1] = mult[FACE_U_CCW][f.cube[0]];
t.cube[5] = mult[FACE_U_CCW][f.cube[1]];
break;
case RF:
t.cube[1] = mult[FACE_L_CCW][f.cube[3]];
t.cube[5] = mult[FACE_L_CCW][f.cube[1]];
t.cube[3] = mult[FACE_L_CCW][f.cube[7]];
t.cube[7] = mult[FACE_L_CCW][f.cube[5]];
break;
case RR:
t.cube[3] = mult[FACE_L_CW][f.cube[1]];
t.cube[1] = mult[FACE_L_CW][f.cube[5]];
t.cube[7] = mult[FACE_L_CW][f.cube[3]];
t.cube[5] = mult[FACE_L_CW][f.cube[7]];
break;
}
}
private static boolean solved(cubeT x){
//上U
char col = lcols[mult[FACE_F_CCW][x.cube[4]]];
if(lcols[mult[FACE_F_CCW][x.cube[5]]] != col) return false;
if(lcols[mult[FACE_F_CCW][x.cube[0]]] != col) return false;
if(lcols[mult[FACE_F_CCW][x.cube[1]]] != col) return false;
//左L
col = lcols[x.cube[4]];
if(lcols[x.cube[0]] != col) return false;
if(lcols[x.cube[6]] != col) return false;
if(lcols[x.cube[2]] != col) return false;
//前F
col = lcols[mult[FACE_U_CW][x.cube[0]]];
if(lcols[mult[FACE_U_CW][x.cube[1]]] != col) return false;
if(lcols[mult[FACE_U_CW][x.cube[2]]] != col) return false;
if(lcols[mult[FACE_U_CW][x.cube[3]]] != col) return false;
//右R
col = lcols[mult[FACE_U_180][x.cube[1]]];
if(lcols[mult[FACE_U_180][x.cube[5]]] != col) return false;
if(lcols[mult[FACE_U_180][x.cube[3]]] != col) return false;
if(lcols[mult[FACE_U_180][x.cube[7]]] != col) return false;
//后B
col = lcols[mult[FACE_U_CCW][x.cube[5]]];
if(lcols[mult[FACE_U_CCW][x.cube[4]]] != col) return false;
if(lcols[mult[FACE_U_CCW][x.cube[7]]] != col) return false;
if(lcols[mult[FACE_U_CCW][x.cube[6]]] != col) return false;
//下D
col = lcols[mult[FACE_F_CW][x.cube[2]]];
if(lcols[mult[FACE_F_CW][x.cube[3]]] != col) return false;
if(lcols[mult[FACE_F_CW][x.cube[6]]] != col) return false;
if(lcols[mult[FACE_F_CW][x.cube[7]]] != col) return false;
return true;
}
private static boolean IDsearch(cubeT x, int maxdepth){
for(int t=0; t<=maxdepth; t++){
boolean res = backtrack(t,x);
if(res){
minmov = t;
return res;
}
}
return false;
}
private static void outsol(boolean ress){
if(!ress)
System.out.println("No Solution!");
else{
System.out.println(minmov);
for(int j=minmov-1; j>=0; j--)
System.out.print(moveOut[res[j]]+" ");
}
}
private static void setCube(cubeT x, char[] s){
int[][] cube = new int[6][4];
int[] colors = new int[256];
int i,j;
colors['w'] = 0; colors['O'] = 1;
colors['G'] = 2; colors['R'] = 3;
colors['Y'] = 4; colors['B'] = 5;
for(i=0; i<8; i++)
x.cube[i] = 0;
for(i=0; i<6; i++)
for(j=0; j<4; j++)
cube[i][j] = i;
for(i=0; i<6; i++)
for(j=0; j<4; j++)
cube[i][j] = colors[s[i*4+j]];
for(i=0; i<24; i++){
rc[i] = lc[mult[FACE_U_180][i]];
fc[i] = lc[mult[FACE_U_CW][i]];
bc[i] = lc[mult[FACE_U_CCW][i]];
uc[i] = lc[mult[FACE_F_CCW][i]];
dc[i] = lc[mult[FACE_F_CW][i]];
}
for(i=0; i<24; i++){
if(uc[i]==cube[0][2] && lc[i]==cube[1][1] && fc[i]==cube[2][0]) x.cube[0]=i;
if(uc[i]==cube[0][3] && fc[i]==cube[2][1] && rc[i]==cube[3][0]) x.cube[1]=i;
if(lc[i]==cube[1][3] && fc[i]==cube[2][2] && dc[i]==cube[5][0]) x.cube[2]=i;
if(fc[i]==cube[2][3] && rc[i]==cube[3][2] && dc[i]==cube[5][1]) x.cube[3]=i;
if(uc[i]==cube[0][0] && lc[i]==cube[1][0] && bc[i]==cube[4][1]) x.cube[4]=i;
if(uc[i]==cube[0][1] && rc[i]==cube[3][1] && bc[i]==cube[4][0]) x.cube[5]=i;
if(lc[i]==cube[1][2] && bc[i]==cube[4][3] && dc[i]==cube[5][2]) x.cube[6]=i;
if(rc[i]==cube[3][3] && bc[i]==cube[4][2] && dc[i]==cube[5][3]) x.cube[7]=i;
}
}
private static void init(){
cubeT x = new cubeT();
cubeT y = new cubeT();
for(int i=0; i<24; i++)
for(int j=0; j<24; j++){
for(int k=0; k<8; k++)
x.cube[k] = k;
smove(x,j);
smove(x,i);
for(int p=0; p<24; p++){
for(int k=0; k<8; k++)
y.cube[k] = k;
smove(y,p);
if(equal(x,y)){
mult[i][j] = p;
break;
}
}
}
}
private static void smove(cubeT t, int snum){
switch (snum){
case ID:
break;
case FACE_U_CW:
swap4(t,0,4,5,1);
swap4(t,2,6,7,3);
break;
case FACE_U_CCW:
swap4(t,0,1,5,4);
swap4(t,2,3,7,6);
break;
case FACE_U_180:
swap2(t,0,5);
swap2(t,1,4);
swap2(t,2,7);
swap2(t,3,6);
break;
case FACE_L_CW:
swap4(t,0,2,6,4);
swap4(t,1,3,7,5);
break;
case FACE_L_CCW:
swap4(t,0,4,6,2);
swap4(t,1,5,7,3);
break;
case FACE_L_180:
swap2(t,0,6);
swap2(t,1,7);
swap2(t,2,4);
swap2(t,3,6);
break;
case FACE_F_CW:
swap4(t,0,1,3,2);
swap4(t,4,5,7,6);
break;
case FACE_F_CCW:
swap4(t,0,2,3,1);
swap4(t,4,6,7,5);
break;
case FACE_F_180:
swap2(t,0,3);
swap2(t,1,2);
swap2(t,4,7);
swap2(t,5,6);
break;
case CORNER_0_CW:
swap3(t,1,2,4);
swap3(t,3,6,5);
break;
case CORNER_0_CCW:
swap3(t,1,4,2);
swap3(t,3,5,6);
break;
case CORNER_2_CW:
swap3(t,0,5,3);
swap3(t,2,4,7);
break;
case CORNER_2_CCW:
swap3(t,0,3,5);
swap3(t,2,7,4);
break;
case CORNER_5_CW:
swap3(t,0,3,6);
swap3(t,1,7,4);
break;
case CORNER_5_CCW:
swap3(t,0,6,3);
swap3(t,1,4,7);
break;
case CORNER_7_CW:
swap3(t,0,5,6);
swap3(t,1,7,2);
break;
case CORNER_7_CCW:
swap3(t,0,6,5);
swap3(t,1,2,7);
break;
case EDGE_1:
swap2(t,0,1);
swap2(t,2,5);
swap2(t,3,4);
swap2(t,6,7);
break;
case EDGE_3:
swap2(t,0,2);
swap2(t,1,6);
swap2(t,3,4);
swap2(t,5,7);
break;
case EDGE_4:
swap2(t,0,7);
swap2(t,1,3);
swap2(t,2,5);
swap2(t,4,6);
break;
case EDGE_6:
swap2(t,0,7);
swap2(t,1,6);
swap2(t,2,3);
swap2(t,4,5);
break;
case EDGE_8:
swap2(t,0,4);
swap2(t,1,6);
swap2(t,2,5);
swap2(t,3,7);
break;
case EDGE_9:
swap2(t,0,7);
swap2(t,1,5);
swap2(t,2,6);
swap2(t,3,4);
break;
}
}
private static void swap2(cubeT t, int a, int b){
int A = t.cube[a];
int B = t.cube[b];
t.cube[b] = A;
t.cube[a] = B;
}
private static void swap3(cubeT t, int a, int b, int c){
int A = t.cube[a];
int B = t.cube[b];
int C = t.cube[c];
t.cube[b] = A;
t.cube[c] = B;
t.cube[a] = C;
}
private static void swap4(cubeT t, int a, int b, int c, int d){
int A = t.cube[a];
int B = t.cube[b];
int C = t.cube[c];
int D = t.cube[d];
t.cube[b] = A;
t.cube[c] = B;
t.cube[d] = C;
t.cube[a] = D;
}
private static boolean equal(cubeT x, cubeT y){
for(int i=0; i<8; i++)
if(x.cube[i] != y.cube[i])
return false;
return true;
}
}
Input & Output
G W
G R
W W
O O
O G
B G
B R
B R
Y R
Y W
Y O
Y B
2
R U
W Y
Y W
R B
O R
O O
W G
G O
R R
W G
Y B
Y B
G B
7
R- F- U- F U F F
Reference
王晓东《计算机算法设计与分析》

该博客探讨了2×2×2魔方问题,旨在设计一个算法以确定从初始状态到达每个面都为单一颜色的目标状态所需的最少旋转次数。文章介绍了问题描述,提供了Java实现,并详细说明了输入和输出格式。
3万+

被折叠的 条评论
为什么被折叠?



