codevs1225八数码难题

Posted 那一抹落日的橙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codevs1225八数码难题相关的知识,希望对你有一定的参考价值。

为了做这个题,我足足花了一个晚自习,才处理好所有的细节问题,太琐碎了

现在复习知识的同时,也会穿插上一些曾经学过但是了解不深的问题,比如a*

a*最重要的就是通过估价函数来大大优化搜索,估价函数是整个a*的灵魂,通过估价函数,可以省去大量的不必要的状态,是一个非常高效的算法。

其他话都写在代码里了,考初赛考的都快虚脱了╮(╯▽╰)╭辣鸡ccf,居然连页脚下方的几几年初赛都写错了,出的题目简直爆炸,今年复赛怕不是药丸

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cmath>
#define ri register int
const int mod=100003;
using namespace std;
bool flag[100010];
int ans,e[10][2],fx[4]={-1,0,1,0},fy[4]={0,1,0,-1};
struct in
{
    int mmp[4][4];//地图 
    int ha,rx,ry,as,mn,ca;//hash值,0的坐标,当前状态步数,以及状态被压成串 
    bool operator <(const in &a)const
    {
        return mn+as>a.mn+a.as;//估价函数g(i)是所有点与答案当中该点所在位置的曼哈顿距离之和 
    }
}st,ed;
priority_queue<in>qwq;
inline void hash(in &x)//求hash值,用于去重 
{
    int re=1;
    for(ri i=1;i<=3;i++)
        for(ri j=1;j<=3;j++)
            re=(re*26+x.mmp[i][j])%mod;
    x.ha=re%mod;
    return;
}
inline void chu(in &a,int x)//提前预处理好状态的估价函数,0所在的位置和hash值 
{
    a.ca=x,a.mn=0;
    int mo=100000000,shu=0;
    for(ri i=1;i<=9;i++)
    {
        shu=x/mo,a.mmp[(i-1)/3+1][i-(i-1)/3*3]=shu,x=x-x/mo*mo;
        a.mn+=abs((i-1)/3+1-e[shu][0])+abs(i-(i-1)/3*3-e[shu][1]);
        if(shu==0)
            a.rx=(i-1)/3+1,a.ry=i-(i-1)/3*3;
        mo/=10;
    }
    hash(a);
}
inline void ya(in &a)//将状态压缩成串 
{
    a.ca=0;
    for(ri i=1;i<=3;i++)
        for(ri j=1;j<=3;j++)
            a.ca=a.ca*10+a.mmp[i][j];
}
int n;
inline void bfs()//a* 
{
    while(!qwq.empty())
    {
        in qaq=qwq.top(),to;
        qwq.pop();
        if(qaq.ha==ed.ha)
        {
            ans=qaq.as;return;
        }
        to.as=qaq.as+1;
        for(ri i=0;i<4;i++)
        {
            to.rx=qaq.rx+fx[i],to.ry=qaq.ry+fy[i];
            if(to.rx<1||to.rx>3||to.ry<1||to.ry>3)
                continue;
            for(int i=1;i<=3;i++)
                for(int j=1;j<=3;j++)
                    to.mmp[i][j]=qaq.mmp[i][j];
            swap(to.mmp[to.rx][to.ry],to.mmp[qaq.rx][qaq.ry]);
            ya(to);
            chu(to,to.ca);
            if(!flag[to.ha])
                flag[to.ha]=1,qwq.push(to);
            swap(to.mmp[to.rx][to.ry],to.mmp[qaq.rx][qaq.ry]); 
        }
    }
}
int main()
{
    scanf("%d",&n);
    int m=100000000,shu=0,n1=123804765;
    for(int i=1;i<=9;i++)
    {
        shu=n1/m;
        e[shu][0]=(i-1)/3+1,e[shu][1]=i-(i-1)/3*3;//预处理好答案中的每种数字所在位置,便于一会求估价函数 
        n1=n1-n1/m*m,m/=10;
    }
    chu(st,n),chu(ed,123804765);//对这两个状态进行预处理,做好加入队列的准备 
    ya(st),ya(ed);//把状态压成个串,便于下面处理 
    qwq.push(st);
    bfs();
    printf("%d",ans);
}

 

以上是关于codevs1225八数码难题的主要内容,如果未能解决你的问题,请参考以下文章

双向广搜+hash+康托展开 codevs 1225 八数码难题

codevs1225 八数码难题

CodeVS1225八数码难题

codevs 1225:八数码难题双向广搜

基础练习BFS+A*codevs1225八数码难题题解

1225 八数码难题