UVa1343

/*这道题还是使用迭代加深搜索的方法,其中有很多技巧学习。1.在描述棋盘的时候使用m[24]来记录从上到下,从左到右每个位置上的数字。2.为了方便接下来的移动操作,使用常数数组line[8][7]来记录每条线上的棋子在m中的坐标。3.使用rev数组来记录反向移动,这也就解释了为什么line需要记录返现操作,这样就都变成了正向操作。4.剪枝操作h(),因为每一次移动最多移除一个数
摘要由CSDN通过智能技术生成
/*
这道题还是使用迭代加深搜索的方法,其中有很多技巧学习。
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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值