UVa1343

来源:互联网 发布:程序员的数学pdf 编辑:程序博客网 时间:2024/06/10 19:33
/*
这道题还是使用迭代加深搜索的方法,其中有很多技巧学习。
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<n;++i){
修改数据状态;
dfs(d+1,maxd);
取消数据状态修改;
    }
    return false;
}
int main(){
    数据读入和初始化;
    for(int maxd=1;;++maxd){
if(dfs(0,maxd)){
    输出结果;
    break;
}
}
*/
#include <iostream>
#include<cstdio>
#include<algorithm>
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;
}