HDOJ-1667/TJU4106 The Rotation Game(IDA*搜索)

今天下午学习了一下IDA*算法,收获还是不小的。

关于IDA*算法的和此题的题解见下面博客:

http://blog.csdn.net/urecvbnkuhbh_54245df/article/details/5856756

讲得非常详细,我的代码也算参考上面那篇博客的。

ID即迭代加深(Iterative Deepening),不断加深允许的最大DFS深度,避免了DFS一条到走到死的情况。虽然出现了某些状态重复搜索的弊端,但是从空间上讲,没有像BFS那样耗费大量内存。

A*算法使用估价函数进行剪枝。

同A*一样,难点是找到合适的估价函数。此题的估价函数剪枝为:如果8-中间最多的数的个数>限定的迭代深度-当前DFS深度则退出搜索。


/*************************************************************************
 > File Name: 4106.cpp
 > Author:wangxin 
 > Mail: 
 > Created Time: 2015年07月10日 星期五 16时25分53秒
 ************************************************************************/

#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;

int DEPTH,ansnum;   //迭代深度,中间的数
int map[25];			 //井字格
int midblocks[8]={7,8,9,12,13,16,17,18};  //位于井字中间位置的编号
char ansPath[100];   //存储搜索路径


//判断是否完成搜索
bool Judge(const int* state)
{
   int i;
   for(i=1;i<=7;i++) 
       if(state[midblocks[i]]!=state[midblocks[i-1]])
           return false;
   return true;

}


//进行状态转换
void ChangeState(int *state,int a1,int a2,int a3,int a4,int a5,int a6,int a7)
{
    int temp;
    temp=state[a1];       state[a1]=state[a2]; state[a2]=state[a3];
    state[a3]=state[a4];  state[a4]=state[a5]; state[a5]=state[a6];
    state[a6]=state[a7];  state[a7]=temp;

}

//计算中间出现最多的数字的个数
int CountMaxSameNum(const int* state)
{
    int i,j,cntarr[4];
    memset(cntarr,0,sizeof(cntarr));
    for(i=0;i<8;i++) cntarr[state[midblocks[i]]]++;
    j=0;
    for(i=1;i<=3;i++)
        if(cntarr[i]>cntarr[j]) j=i;
    return cntarr[j];
}


//DFS函数,返回值表示是否搜索到  curDepth表示当前的搜索深度,preDir表示上一步的变换方向
bool DFS(int *state, int curDepth, int preDir)
{
    int i,j;
    int temp[25]; 

//IDA*估价函数剪枝,如果剩下的搜索深度不可能完成任务,不进行进一步搜索
    if(DEPTH-curDepth < 8-CountMaxSameNum(state))
        return false;
//限定迭代深度
    if(curDepth>DEPTH)
        return false;
//枚举变换的方向
    for(i=1;i<=8;i++)
    {
    //剪枝:连续的方向相反的变换是没有意义的
        if((i==1 && preDir==6)||(i==6 && preDir==1)) continue;
        if((i==2 && preDir==5)||(i==5 && preDir==2)) continue;
        if((i==3 && preDir==8)||(i==8 && preDir==3)) continue;
        if((i==4 && preDir==7)||(i==7 && preDir==4)) continue;

        for(j=1;j<=24;j++) temp[j]=state[j];

        switch(i)
        {
            case 1:ansPath[curDepth]='A'; ChangeState(temp, 1, 3, 7,12,16,21,23);break;
            case 2:ansPath[curDepth]='B'; ChangeState(temp, 2, 4, 9,13,18,22,24);break;
            case 3:ansPath[curDepth]='C'; ChangeState(temp,11,10, 9, 8, 7, 6, 5);break;
            case 4:ansPath[curDepth]='D'; ChangeState(temp,20,19,18,17,16,15,14);break;
            case 5:ansPath[curDepth]='E'; ChangeState(temp,24,22,18,13, 9, 4, 2);break;
            case 6:ansPath[curDepth]='F'; ChangeState(temp,23,21,16,12, 7, 3, 1);break;
            case 7:ansPath[curDepth]='G'; ChangeState(temp,14,15,16,17,18,19,20);break;
            case 8:ansPath[curDepth]='H'; ChangeState(temp, 5, 6, 7, 8, 9,10,11);break;
            default: printf("There is something wrong!");
        }
        
        //如果检测到搜索成功,返回true
        if (Judge(temp))
        {
            ansnum=temp[7];
            ansPath[curDepth+1]='\0';
            return true;
        }

        if (DFS(temp,curDepth+1,i)) return true;
    }
    return false; 
}


void work()
{
    int i,j,k,t,m,n;
    
    for(i=2;i<=24;i++) scanf("%d",&map[i]);

    if(Judge(map))
    {
        printf("No moves needed\n");
        printf("%d\n",map[7]);
    }
    else
    {
    //限定初始的迭代深度
        DEPTH=1;
        while(1)
        {
            if(DFS(map,0,-1)) break;
            DEPTH++;
            //如果在当前迭代深度下没有搜出答案,加大搜索深度
        }
        printf("%s\n",ansPath);
        printf("%d\n",ansnum);
    }

}

int main()
{
    while(scanf("%d",&map[1]),map[1])
    {
        work();
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值