题解:这一题用IDA*算法。首先要打表,把每个格子从上到,下从左到右依次编号。然后每个方向也依次编号,我用block数组。然后中间的一圈也编号,用于最后判断是否一致。重点在于估值函数h()的写法。我们发现每次移动也给方向,数字最多改变一个,所以如果(目前步数+要改变的最小的次数)> 最大的步数,那么剪枝。
代码:
#include <bits/stdc++.h>
using namespace std;
int block[8][7] = {{0,2,6,11,15,20,22}, //编号每一个格子
{1,3,8,12,17,21,23},
{10,9,8,7,6,5,4},
{19,18,17,16,15,14,13},
{23,21,17,12,8,3,1},
{22,20,15,11,6,2,0},
{13,14,15,16,17,18,19},
{4,5,6,7,8,9,10}
};
int center[8] = {6,7,8,12,17,16,15,11}; //中心一圈的格子编号
int a[30]; //记录每一个格子的数字
char m[1000]; //记录旋转的路径
int rev[8] = {5,4,7,6,1,0,3,2};
bool goal(){
for(int i=1;i<8;i++)
if(a[center[i]] != a[6]) return false;
return true;
}
int differ(int num){
int cnt = 0;
for(int i=0;i<8;i++)
if(a[center[i]] != num) cnt++;
return cnt;
}
int h(){ //估值函数,每一次旋转最多使中心多一个
return min(min(differ(1),differ(2)),differ(3));
}
void rotation(int dir){ //旋转方向
int tmp = a[block[dir][0]];
for(int i=1;i<7;i++)
a[block[dir][i-1]] = a[block[dir][i]];
a[block[dir][6]] = tmp;
}
bool dfs(int step,int maxd){
if(step + h() > maxd) return false;
if(goal()){
m[step] = '\0';
printf("%s\n",m);
return true;
}
for(int i=0;i<8;i++){
m[step] = 'A' + i;
rotation(i);
if(dfs(step+1,maxd)) return true;
rotation(rev[i]);
}
return false;
}
int main(){
while(~scanf("%d",&a[0]) && a[0]){
for(int i=1;i<24;i++) scanf("%d",&a[i]);
if(goal())
printf("No moves needed\n");
else{
for(int maxd=1;;maxd++) if(dfs(0,maxd)) break;
}
printf("%d\n",a[6]);
}
return 0;
}