关闭

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

标签: acmhdoj搜索算法IDA
250人阅读 评论(0) 收藏 举报
分类:

今天下午学习了一下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

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:21171次
    • 积分:997
    • 等级:
    • 排名:千里之外
    • 原创:81篇
    • 转载:3篇
    • 译文:0篇
    • 评论:2条
    文章分类
    最新评论