紫书代码详见代码内注释
#include<bits/stdc++.h>
using namespace std;
int a[24];
char ans[1050];
/* 坐标分布图
00 01
02 03
04 05 06 07 08 09 10
11 12
13 14 15 16 17 18 19
20 21
22 23
*/
int line[8][7]={
{ 0, 2, 6,11,15,20,22}, // A
{ 1, 3, 8,12,17,21,23}, // B
{10, 9, 8, 7, 6, 5, 4}, // C
{19,18,17,16,15,14,13}, // D
};
const int center[8] = {6, 7, 8, 11, 12, 15, 16, 17}; //中心的坐标
bool is_final(){ //判断是否达成结果
for(int i=0;i<8;i++){
if(a[center[i]]!=a[center[0]]){
return 0;
}
}
return 1;
}
int dff(int x){ //和h()配合使用
int cnt=0;
for(int i=0;i<8;i++){
if(a[center[i]]!=x){cnt++;}
}
return cnt;
}
int h(){
return min(min(dff(1),dff(2)),dff(3)); //找出三个数字中对应成功最少的
}
void move(int i){ //环状移动
int tmp=a[line[i][0]];
for(int j=0;j<6;j++){
a[line[i][j]]=a[line[i][j+1]];
}
a[line[i][6]]=tmp;
}
const int rev[8] = {5, 4, 7, 6, 1, 0, 3, 2}; //对面的line里面的i操作 例如line 里面i==0时为A操作而F操作才能使还原所以才rev里i==0时rev[0]==5代表line[5]的F操作
bool dfs(int d,int maxd){
if(is_final()){ //达成后把字符数组以字符串形式输出
ans[d]='\0';
printf("%s\n",ans);
return 1;
}
if(d+h()>maxd)return 0; //剪枝 剩余最大操作数小于错误数肯定就能直接剪
for(int i=0;i<8;i++){
ans[d]='A'+i;
move(i);
if(dfs(d+1,maxd))return 1;
move(rev[i]);
}
return 0;
}
int main(){
for(int i=4;i<8;i++)
for(int j=0;j<7;j++){
line[i][j]=line[rev[i]][6-j]; //减少人工,把EFGH的标号弄出来
}
while(scanf("%d",&a[0])==1&&a[0]){
for(int i=1;i<24;i++)scanf("%d",&a[i]);
for(int i=0;i<24;i++){
if(!a[i])return 0;
}
if(is_final()){
printf("No moves needed\n");
}
else {
for(int maxd=1;;maxd++){//一定有解 不用设置上限
if(dfs(0,maxd))break;
}
}
printf("%d\n",a[8]);
}
return 0;
}