/*
这道题还是使用迭代加深搜索的方法,其中有很多技巧学习。
1.在描述棋盘的时候使用m[24]来记录从上到下,从左到右每个位置上的数字。
2.为了方便接下来的移动操作,使用常数数组line[8][7]来记录每条线上的棋子在m中的坐标。
3.使用rev数组来记录反向移动,这也就解释了为什么line需要记录返现操作,这样就都变成了正向操作。
4.剪枝操作h(),因为每一次移动最多移除一个数字,因此如果当前1,2,3中需要移动次数最少的数字都超过maxd-d,那么当前maxd下该解不可行。
这里总结一下迭代加深搜索方法,该方法对于搜索问题适用性很强,包括很多可以使用DFS和BFS的问题也可以使用该方法。
这种方法的特点就是不知道需要多少步可以取得可行解,因此就从1步开始尝试,如果1步不行,就2步,依次增加搜索深度
中间最关键的步骤是剪枝,可以大大加快搜索速度。
其伪代码如下:
void dfs(int d,int maxd){
if(取得可行解){
输出结果;
return true;
}
剪枝;如(d>maxd,这是最基本的剪枝)
//接下来进行加深搜索
for(int i=0;i
修改数据状态;
dfs(d+1,maxd);
取消数据状态修改;
}
return false;
}
int main(){
数据读入和初始化;
for(int maxd=1;;++maxd){
if(dfs(0,maxd)){
输出结果;
break;
}
}
*/
#include
#include
#include
using namespace std;
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
{23,21,17,12,8,3,1},//E
{22,20,15,11,6,2,0},//F
{13,14,15,16,17,18,19},//G
{4,5,6,7,8,9,10}//H
};
int m[24];
char ch[1000];
int rev[8]={5,4,7,6,1,0,3,2};
int center[8]={6,7,8,11,12,15,16,17};
bool is_final(){
for(int i=1;i<8;++i){
if(m[center[i]]!=m[center[0]])return false;
}
return true;
}
int diff(int target){
int ans=0;
for(int i=0;i<8;++i)ans+=m[center[i]]!=target?1:0;
return ans;
}
int h(){
return min(diff(1),min(diff(2),diff(3)));
}
void move(int n){
int tmp=m[line[n][0]];
for(int i=0;i<6;++i)m[line[n][i]]=m[line[n][i+1]];
m[line[n][6]]=tmp;
}
bool dfs(int d,int maxd){
if(is_final()){
ch[d]='\0';
printf("%s\n",ch);
return true;
}
if(d+h()>maxd)return false;
for(int i=0;i<8;++i){
ch[d]='A'+i;
move(i);
if(dfs(d+1,maxd))return true;
move(rev[i]);
}
return false;
}
int main()
{
while(scanf("%d",&(m[0]))==1&&m[0]){
for(int i=1;i<24;++i)scanf("%d",&(m[i]));
if(is_final())printf("No moves needed\n");
else{
for(int maxd=1;;++maxd){
if(dfs(0,maxd))break;
}
}
printf("%d\n",m[6]);
}
return 0;
}