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

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

Java
package Chapter5HuiSuFa;
import java.util.Arrays;
import java.util.Scanner;
public class MoFangRubiksCube {
private static class cubeT{
int[] cube = new int[20];
}
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 BF = 2;//后面顺时针
private static final int BR = 3;//后面逆时针
private static final int LF = 4;//左面顺时针
private static final int LR = 5;//左面逆时针
private static final int RF = 6;//右面顺时针
private static final int RR = 7;//右面逆时针
private static final int UF = 8;//上面顺时针
private static final int UR = 9;//上面逆时针
private static final int DF = 10;//底面顺时针
private static final int DR = 11;//底面逆时针
private static String[] moveOut = {"F","F-","B","B-","L","L-","R","R-","U","U-","D","D-"};
private static int[][] mult;
private static int[] res;
private static int minmov,maxdepth=100;
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[54];
String[] str = new String[54];
init();
for(int i=0; i<54; i++)
str[i] = input.next();
for(int i=0; i<54; 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[12];
boolean result = false;
if(depth == 0){
if(solved(p)){
return true;
}else
return false;
}
for(int i=0; i<12; 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, 20);
t.cube = cube;
switch (mv){
case FF:
t.cube[0] = mult[FACE_F_CW][f.cube[5]];
t.cube[1] = mult[FACE_F_CW][f.cube[3]];
t.cube[2] = mult[FACE_F_CW][f.cube[0]];
t.cube[3] = mult[FACE_F_CW][f.cube[6]];
t.cube[4] = mult[FACE_F_CW][f.cube[1]];
t.cube[5] = mult[FACE_F_CW][f.cube[7]];
t.cube[6] = mult[FACE_F_CW][f.cube[4]];
t.cube[7] = mult[FACE_F_CW][f.cube[2]];
break;
case FR:
t.cube[5] = mult[FACE_F_CCW][f.cube[0]];
t.cube[3] = mult[FACE_F_CCW][f.cube[1]];
t.cube[0] = mult[FACE_F_CCW][f.cube[2]];
t.cube[6] = mult[FACE_F_CCW][f.cube[3]];
t.cube[1] = mult[FACE_F_CCW][f.cube[4]];
t.cube[7] = mult[FACE_F_CCW][f.cube[5]];
t.cube[4] = mult[FACE_F_CCW][f.cube[6]];
t.cube[2] = mult[FACE_F_CCW][f.cube[7]];
break;
case UF:
t.cube[12] = mult[FACE_U_CW][f.cube[0]];
t.cube[13] = mult[FACE_U_CW][f.cube[8]];
t.cube[14] = mult[FACE_U_CW][f.cube[12]];
t.cube[8] = mult[FACE_U_CW][f.cube[1]];
t.cube[9] = mult[FACE_U_CW][f.cube[13]];
t.cube[0] = mult[FACE_U_CW][f.cube[2]];
t.cube[1] = mult[FACE_U_CW][f.cube[9]];
t.cube[2] = mult[FACE_U_CW][f.cube[14]];
break;
case UR:
t.cube[0] = mult[FACE_U_CCW][f.cube[12]];
t.cube[8] = mult[FACE_U_CCW][f.cube[13]];
t.cube[12] = mult[FACE_U_CCW][f.cube[14]];
t.cube[1] = mult[FACE_U_CCW][f.cube[8]];
t.cube[13] = mult[FACE_U_CCW][f.cube[9]];
t.cube[2] = mult[FACE_U_CCW][f.cube[0]];
t.cube[9] = mult[FACE_U_CCW][f.cube[1]];
t.cube[14] = mult[FACE_U_CCW][f.cube[2]];
break;
case RF:
t.cube[2] = mult[FACE_L_CCW][f.cube[7]];
t.cube[9] = mult[FACE_L_CCW][f.cube[4]];
t.cube[14] = mult[FACE_L_CCW][f.cube[2]];
t.cube[4] = mult[FACE_L_CCW][f.cube[11]];
t.cube[16] = mult[FACE_L_CCW][f.cube[9]];
t.cube[7] = mult[FACE_L_CCW][f.cube[19]];
t.cube[11] = mult[FACE_L_CCW][f.cube[16]];
t.cube[19] = mult[FACE_L_CCW][f.cube[14]];
break;
case RR:
t.cube[7] = mult[FACE_L_CW][f.cube[2]];
t.cube[4] = mult[FACE_L_CW][f.cube[9]];
t.cube[2] = mult[FACE_L_CW][f.cube[14]];
t.cube[11] = mult[FACE_L_CW][f.cube[4]];
t.cube[9] = mult[FACE_L_CW][f.cube[16]];
t.cube[19] = mult[FACE_L_CW][f.cube[7]];
t.cube[16] = mult[FACE_L_CW][f.cube[11]];
t.cube[14] = mult[FACE_L_CW][f.cube[19]];
break;
case LF:
t.cube[12] = mult[FACE_L_CW][f.cube[17]];
t.cube[8] = mult[FACE_L_CW][f.cube[15]];
t.cube[0] = mult[FACE_L_CW][f.cube[12]];
t.cube[15] = mult[FACE_L_CW][f.cube[10]];
t.cube[3] = mult[FACE_L_CW][f.cube[8]];
t.cube[17] = mult[FACE_L_CW][f.cube[5]];
t.cube[10] = mult[FACE_L_CW][f.cube[3]];
t.cube[5] = mult[FACE_L_CW][f.cube[0]];
break;
case LR:
t.cube[17] = mult[FACE_L_CCW][f.cube[12]];
t.cube[15] = mult[FACE_L_CCW][f.cube[8]];
t.cube[12] = mult[FACE_L_CCW][f.cube[0]];
t.cube[10] = mult[FACE_L_CCW][f.cube[15]];
t.cube[8] = mult[FACE_L_CCW][f.cube[3]];
t.cube[5] = mult[FACE_L_CCW][f.cube[17]];
t.cube[3] = mult[FACE_L_CCW][f.cube[10]];
t.cube[0] = mult[FACE_L_CCW][f.cube[5]];
break;
case DF:
t.cube[5] = mult[FACE_U_CCW][f.cube[17]];
t.cube[6] = mult[FACE_U_CCW][f.cube[10]];
t.cube[7] = mult[FACE_U_CCW][f.cube[5]];
t.cube[10] = mult[FACE_U_CCW][f.cube[18]];
t.cube[11] = mult[FACE_U_CCW][f.cube[6]];
t.cube[17] = mult[FACE_U_CCW][f.cube[19]];
t.cube[18] = mult[FACE_U_CCW][f.cube[11]];
t.cube[19] = mult[FACE_U_CCW][f.cube[7]];
break;
case DR:
t.cube[17] = mult[FACE_U_CW][f.cube[5]];
t.cube[10] = mult[FACE_U_CW][f.cube[6]];
t.cube[5] = mult[FACE_U_CW][f.cube[7]];
t.cube[18] = mult[FACE_U_CW][f.cube[10]];
t.cube[6] = mult[FACE_U_CW][f.cube[11]];
t.cube[19] = mult[FACE_U_CW][f.cube[17]];
t.cube[11] = mult[FACE_U_CW][f.cube[18]];
t.cube[7] = mult[FACE_U_CW][f.cube[19]];
break;
case BF:
t.cube[14] = mult[FACE_F_CCW][f.cube[19]];
t.cube[13] = mult[FACE_F_CCW][f.cube[16]];
t.cube[12] = mult[FACE_F_CCW][f.cube[14]];
t.cube[16] = mult[FACE_F_CCW][f.cube[18]];
t.cube[15] = mult[FACE_F_CCW][f.cube[13]];
t.cube[19] = mult[FACE_F_CCW][f.cube[17]];
t.cube[18] = mult[FACE_F_CCW][f.cube[15]];
t.cube[17] = mult[FACE_F_CCW][f.cube[12]];
break;
case BR:
t.cube[19] = mult[FACE_F_CW][f.cube[14]];
t.cube[16] = mult[FACE_F_CW][f.cube[13]];
t.cube[14] = mult[FACE_F_CW][f.cube[12]];
t.cube[18] = mult[FACE_F_CW][f.cube[16]];
t.cube[13] = mult[FACE_F_CW][f.cube[15]];
t.cube[17] = mult[FACE_F_CW][f.cube[19]];
t.cube[15] = mult[FACE_F_CW][f.cube[18]];
t.cube[12] = mult[FACE_F_CW][f.cube[17]];
break;
}
}
private static boolean solved(cubeT x){
for(int i=0; i<20; i++)
if(x.cube[i] > 0)
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][9];
int[] colors = new int[256];
int i,j;
for(i=0; i<20; i++)
x.cube[i] = 24;
for(i=0; i<6; i++)
for(j=0; j<9; j++)
cube[i][j] = s[i*9+j];
for(i=0; i<256; i++)
colors[i] = 255;
for(i=0; i<6; i++)
colors[cube[i][4]] = i;
for(i=0; i<6; i++)
for(j=0; j<9; j++)
cube[i][j] = colors[cube[i][j]];
for(i=0; i<6; i++)
for(j=0; j<9; j++)
if(cube[i][j] == 255){
System.out.println("bad color in cube!");
return;
}
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][6] && lc[i]==cube[1][2] && fc[i]==cube[2][0]) x.cube[0]=i;
if(uc[i]==cube[0][8] && fc[i]==cube[2][2] && rc[i]==cube[3][0]) x.cube[2]=i;
if(lc[i]==cube[1][8] && fc[i]==cube[2][6] && dc[i]==cube[5][0]) x.cube[5]=i;
if(fc[i]==cube[2][8] && rc[i]==cube[3][6] && dc[i]==cube[5][2]) x.cube[7]=i;
if(uc[i]==cube[0][0] && lc[i]==cube[1][0] && bc[i]==cube[4][2]) x.cube[12]=i;
if(uc[i]==cube[0][2] && rc[i]==cube[3][2] && bc[i]==cube[4][0]) x.cube[14]=i;
if(lc[i]==cube[1][6] && bc[i]==cube[4][8] && dc[i]==cube[5][6]) x.cube[17]=i;
if(rc[i]==cube[3][8] && bc[i]==cube[4][6] && dc[i]==cube[5][8]) x.cube[19]=i;
//边块
if(uc[i]==cube[0][7] && fc[i]==cube[2][1]) x.cube[1]=i;
if(lc[i]==cube[1][5] && fc[i]==cube[2][3]) x.cube[3]=i;
if(fc[i]==cube[2][5] && rc[i]==cube[3][3]) x.cube[4]=i;
if(fc[i]==cube[2][7] && dc[i]==cube[5][1]) x.cube[6]=i;
if(uc[i]==cube[0][3] && lc[i]==cube[1][1]) x.cube[8]=i;
if(uc[i]==cube[0][5] && rc[i]==cube[3][1]) x.cube[9]=i;
if(lc[i]==cube[1][7] && dc[i]==cube[5][3]) x.cube[10]=i;
if(rc[i]==cube[3][7] && dc[i]==cube[5][5]) x.cube[11]=i;
if(uc[i]==cube[0][1] && bc[i]==cube[4][1]) x.cube[13]=i;
if(lc[i]==cube[1][3] && bc[i]==cube[4][5]) x.cube[15]=i;
if(rc[i]==cube[3][5] && bc[i]==cube[4][3]) x.cube[16]=i;
if(bc[i]==cube[4][7] && dc[i]==cube[5][7]) x.cube[18]=i;
}
for(i=0; i<20; i++)
if(x.cube[i] == 24){
System.out.println("bad cube description!");
return;
}
}
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<20; k++)
x.cube[k] = k;
smove(x,j);
smove(x,i);
for(int p=0; p<24; p++){
for(int k=0; k<20; 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,12,14,2);
swap4(t,1,8,13,9);
swap4(t,3,15,16,4);
swap4(t,5,17,19,7);
swap4(t,6,10,18,11);
break;
case FACE_U_CCW:
swap4(t,0,2,14,12);
swap4(t,1,9,13,8);
swap4(t,3,4,16,15);
swap4(t,5,7,19,17);
swap4(t,6,11,18,10);
break;
case FACE_U_180:
swap2(t,0,14);
swap2(t,1,13);
swap2(t,2,12);
swap2(t,3,16);
swap2(t,4,15);
swap2(t,5,19);
swap2(t,6,18);
swap2(t,7,17);
swap2(t,8,9);
swap2(t,10,11);
break;
case FACE_L_CW:
swap4(t,0,5,17,12);
swap4(t,3,10,15,8);
swap4(t,1,6,18,13);
swap4(t,2,7,19,14);
swap4(t,4,11,16,9);
break;
case FACE_L_CCW:
swap4(t,0,12,17,5);
swap4(t,3,8,15,10);
swap4(t,1,13,18,6);
swap4(t,2,14,19,7);
swap4(t,4,9,16,11);
break;
case FACE_L_180:
swap2(t,0,17);
swap2(t,1,18);
swap2(t,2,19);
swap2(t,3,15);
swap2(t,4,16);
swap2(t,5,12);
swap2(t,6,13);
swap2(t,7,14);
swap2(t,8,10);
swap2(t,9,11);
break;
case FACE_F_CW:
swap4(t,0,2,7,5);
swap4(t,1,4,6,3);
swap4(t,8,9,11,10);
swap4(t,12,14,19,17);
swap4(t,13,16,18,15);
break;
case FACE_F_CCW:
swap4(t,0,5,7,2);
swap4(t,1,3,6,4);
swap4(t,8,10,11,9);
swap4(t,12,17,19,14);
swap4(t,13,15,18,16);
break;
case FACE_F_180:
swap2(t,0,7);
swap2(t,1,6);
swap2(t,2,5);
swap2(t,3,4);
swap2(t,8,11);
swap2(t,9,10);
swap2(t,12,19);
swap2(t,13,18);
swap2(t,14,17);
swap2(t,15,16);
break;
case CORNER_0_CW:
swap3(t,1,3,8);
swap3(t,2,5,12);
swap3(t,4,10,13);
swap3(t,6,15,9);
swap3(t,7,17,14);
swap3(t,11,18,16);
break;
case CORNER_0_CCW:
swap3(t,1,8,3);
swap3(t,2,12,5);
swap3(t,4,13,10);
swap3(t,6,9,15);
swap3(t,7,14,17);
swap3(t,11,16,18);
break;
case CORNER_2_CW:
swap3(t,0,14,7);
swap3(t,1,9,4);
swap3(t,3,13,11);
swap3(t,5,12,19);
swap3(t,6,8,16);
swap3(t,10,15,18);
break;
case CORNER_2_CCW:
swap3(t,0,7,14);
swap3(t,1,4,9);
swap3(t,3,11,13);
swap3(t,5,19,12);
swap3(t,6,16,8);
swap3(t,10,18,15);
break;
case CORNER_5_CW:
swap3(t,0,7,17);
swap3(t,1,11,15);
swap3(t,2,19,12);
swap3(t,3,6,10);
swap3(t,4,18,8);
swap3(t,9,16,13);
break;
case CORNER_5_CCW:
swap3(t,0,17,7);
swap3(t,1,15,11);
swap3(t,2,12,19);
swap3(t,3,10,6);
swap3(t,4,8,18);
swap3(t,9,13,16);
break;
case CORNER_7_CW:
swap3(t,0,14,17);
swap3(t,1,16,10);
swap3(t,2,19,5);
swap3(t,3,9,18);
swap3(t,4,11,6);
swap3(t,8,13,15);
break;
case CORNER_7_CCW:
swap3(t,0,17,14);
swap3(t,1,10,16);
swap3(t,2,5,19);
swap3(t,3,18,9);
swap3(t,4,6,11);
swap3(t,8,15,13);
break;
case EDGE_1:
swap2(t,0,2);
swap2(t,3,9);
swap2(t,4,8);
swap2(t,5,14);
swap2(t,6,13);
swap2(t,7,12);
swap2(t,10,16);
swap2(t,11,15);
swap2(t,17,19);
break;
case EDGE_3:
swap2(t,0,5);
swap2(t,1,10);
swap2(t,2,17);
swap2(t,4,15);
swap2(t,6,8);
swap2(t,7,12);
swap2(t,9,18);
swap2(t,11,13);
swap2(t,14,19);
break;
case EDGE_4:
swap2(t,0,19);
swap2(t,1,11);
swap2(t,2,7);
swap2(t,3,16);
swap2(t,5,14);
swap2(t,6,9);
swap2(t,8,18);
swap2(t,10,13);
swap2(t,12,17);
break;
case EDGE_6:
swap2(t,0,19);
swap2(t,1,18);
swap2(t,2,17);
swap2(t,3,11);
swap2(t,4,10);
swap2(t,5,7);
swap2(t,8,16);
swap2(t,9,15);
swap2(t,12,14);
break;
case EDGE_8:
swap2(t,0,12);
swap2(t,1,15);
swap2(t,2,17);
swap2(t,3,13);
swap2(t,4,18);
swap2(t,5,14);
swap2(t,6,16);
swap2(t,7,19);
swap2(t,9,10);
break;
case EDGE_9:
swap2(t,0,19);
swap2(t,1,16);
swap2(t,2,14);
swap2(t,3,18);
swap2(t,4,13);
swap2(t,5,17);
swap2(t,6,15);
swap2(t,7,12);
swap2(t,8,11);
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<20; i++)
if(x.cube[i] != y.cube[i])
return false;
return true;
}
}
Input & Output
G W W
G W W
G R R
W W W
O O O
O O O
O G G
B G G
B G G
B R R
B R R
B R R
Y Y R
Y Y W
Y Y W
Y O O
Y B B
Y B B
2
L F
B W O
B W G
B B Y
R R R
O O O
Y Y Y
G G B
Y G B
R O B
O R G
O R G
O R G
W R Y
W Y G
W Y O
W W G
W B Y
W B R
6
L F F L R- U
Y W W
W W G
G G W
O Y W
O O Y
W O O
O O Y
O G G
G B G
O B G
R R R
R W R
R R B
B Y W
Y R R
B Y B
B B G
Y Y B
7
U R F- D- L R- D
O W R
G W W
W O W
Y O R
Y O Y
O B O
Y B O
O G G
G W G
G G B
R R G
R R G
Y R W
B Y W
W Y Y
B O B
R B Y
B B R
7
D R F- D- L R- U
Reference
王晓东《计算机算法设计与分析》

本文介绍了如何使用回溯法解决3x3x3魔方问题,从初始状态通过最少次数的旋转达到每个面只有一种颜色的目标状态。文章提供数据输入格式和Java代码实现,参考自王晓东的《计算机算法设计与分析》。
1023

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



