zoukankan      html  css  js  c++  java
  • 八数码问题强化版:十五数码问题idA*版本

    ---恢复内容开始---

    上一次介绍过dbfs版本,这次来介绍idA*版本。

    首先要理解idA*算法的思想,是将迭代加深与A*的结合,将估价函数h(n)作为迭代的限制值,进行dfs。

    (A*和迭代加深的介绍等有时间再写出来吧)

    对所有点(除0以外的)进行曼哈顿距离计算(目标状态到初始状态),h(n)为当前节点的各点的曼哈顿距离和。

    在代码中看:

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define abs(w) (w>=0?w:-(w))
    int xx[20],yy[20],bound,flg;int u[4] = {0,0,1,-1};
    int p[4] = {1,-1,0,0};
    using namespace std;
    struct node{
        int mat[20];
        int pos;
        int H()//计算h(n)
        {
            register int ans(0);
            for(register int i = 0 ; i < 15 ; ++i)
                ans+=abs(xx[mat[i]]-(i>>2))+abs(yy[mat[i]]-(i&3));
            return ans;
        }
        bool check()//判断解的存在性
        {
            register int tot(0),i,j;
            for( i = 0 ; i < 16 ; ++i)
            {
                if(!mat[i])continue;
                for(j = 0 ; j < i ; ++j)
                    if(mat[j]<mat[i])++tot;
            }
            tot+=abs((pos>>2)-3)+abs((pos&3)-3);
            if(tot&1)return true;
            return false;
        }
    }a;
    inline bool ok(register int x,register int y)//防止从走过来的地方再退回去
    {
        if(x>y)swap(x,y);
        if(x==0&y==1)return false;
        if(x==2&&y==3)return false;
        return true;
    }
    int dfs(register int step,register int h,register int las)
    {if(step+h>bound)return step+h;//如果g(n)+h(n)>f(n),就更新f(n)
        if(!h)//到达最终状态,输出g(n)即可
        {
            printf("%d",step);
            flg=1;
            return step;
        }
        register int ret=127,pos=a.pos,x=pos>>2,y=pos&3;
        register int dx,dy,tar,ht,tmp,i;
        for(i = 0 ; i < 4 ; ++i)//向四个方向拓展
        {
             dx=x+u[i];
             dy=y+p[i];
            if(dx<0||dy<0||dx>3||dy>3||!ok(i,las))continue;
             tar=(dx<<2)|dy;//计算拓展出新节点的一维坐标
            a.mat[pos]=a.mat[tar];
            a.mat[tar]=0;//这两行相当于swap操作(据说这样可以快一点)
            a.pos=tar;
             ht=h-(abs(xx[a.mat[pos]]-dx)+abs(yy[a.mat[pos]]-dy)) + abs(xx[a.mat[pos]]-x)+abs(yy[a.mat[pos]]-y) ;//计算新的h值
             tmp=dfs(step+1,ht,i);
            if(flg)return tmp;//找到路径
            if(ret>tmp)ret=tmp;//更新bound
            a.mat[tar]=a.mat[pos];//回溯
            a.mat[pos]=0;
            a.pos=pos;
        }
        return ret;
    }
    int main()
    {
       // freopen("fifteen.in","r",stdin);
      //  freopen("fifteen.out","w",stdout);
        register int k,i;
        for( i = 0 ; i < 16 ; ++i)
        {
            scanf("%d",&k);
            if(!k)a.pos=i;//记录0的位置
            else 
            {
                a.mat[i]=k;
                xx[k]=i>>2;//保存k的二维坐标
                yy[k]=i&3;//相当于i%4
            }
        }if(!a.check())//判断解的存在性
        {
            printf("No");
            return 0;
        }
        for( i = 0 ; i < 16 ; ++i)//从目标状态向初始状态更新,别问我为什么,看各方大佬的代码都是这样(据说是一个小技巧,可以快一点)。
            a.mat[i]=i+1;
        a.mat[15]=0;
        a.pos=15;
        for(bound=a.H();bound<=60;bound=dfs(0,a.H(),4))//idA*部分
            if(flg)break;
        return 0;
    }

    解释一下这个代码中的一些优化的小细节(数据好像有卡常数的):

    1、inline 以及register

    inline 所谓的内联函数,据说可以优化时间。

    register 将空间存在CPU的寄存器中,优化时间。

    借鉴网友的例子,作用相当于口袋中有面包,就不需要跑到百米开外的商店去买,自然时间就快。

    2、i&3相当于i%4

    因为&3相当于保存二进制位的最后三位,即实现了%4的操作,但只适用于%2,4,8这样的2^n数。

    3、对于abs的define 将一些在代码中重复出现的小函数可以采用define 的办法使用,可以达到优化时间的作用。

  • 相关阅读:
    爬虫之字体解密
    【大数据】PySpark 使用 FileSystem 操作 HDFS
    数据读取保存(五)
    Spark SQL 数据源(三)
    hive 之 DML 操作(六)
    【Python】散列的一种实现
    【Python】插入记录并获取其自增ID(PyMysql)
    sbt 编译打包(六)
    Spark SQL (二)
    2022年的第一篇
  • 原文地址:https://www.cnblogs.com/fujudge/p/7398153.html
Copyright © 2011-2022 走看看