zoukankan      html  css  js  c++  java
  • P1379 八数码难题

    原题链接  https://www.luogu.com.cn/problem/P1379

    题解 

    八数码难题,一道十分经典的 $bfs$ 搜索题,所以我们可以用 $bfs$ 来解决这道题;

    一. 单向 $bfs$

    我们可以将这九个格子依次排成一排,这样一个 $3*3$ 的矩阵就可以转化为一个九位数的数字,这样可以方便我们保存状态;

    每走一步就是将 $0$ 上下左右四个方向的数字移到 $0$ 的位置,这样那个数字的位置就空了,就变成了 $0$,那么每走一步就可以看做是将 $0$ 与四周的数字交换的过程;

    从初始状态进行 $bfs$ ,每转移一个新状态就压入队列里,同时记录初始状态到这个新状态的步数,过程中注意判重,直到扩展到目标布局;

    二. 双向 $bfs$

    由于单向 $bfs$ 的时间复杂度忒高,我们可以考虑双向 $bfs$

    双向 $bfs$ 适用于知道起点和终点的状态下使用,从起点和终点两个方向开始进行搜索,可以非常大地提高单个 $bfs$ 的搜索效率;
    同样,实现也是通过队列的方式,可以设置两个队列,一个队列保存从起点开始搜索的状态,另一个队列用来保存从终点开始搜索的状态,如果某一个状态下出现相交的情况,那么就出现了答案;

     思路和单向 $bfs$ 的一样,需要注意的地方代码里详细地注释了哦~

    $Code$:

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cstdio>
    #include<map>
    #include<queue>
    using namespace std;
    int read()
    {
        char ch=getchar();
        int a=0,x=1;
        while(ch<'0'||ch>'9')
        {
            if(ch=='-') x=-x;
            ch=getchar(); 
        }
        while(ch>='0'&&ch<='9')
        {
            a=(a<<1)+(a<<3)+(ch-'0');
            ch=getchar(); 
        }
        return a*x;
    }
    const int E=123804765;
    int S,x,y,Ans;
    int a[4][4],dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
    map<int,int> ans;     //表示搜索到当前状态需要多少步 
    map<int,int> state;   //表示每种状态是正搜得到还是反搜得到 
    queue<int> q;
    void work1(int A)     //数字转化为矩阵 
    {
        int w=100000000;
        for(int i=1;i<=3;i++)
        {
            for(int j=1;j<=3;j++)
            {
                a[i][j]=(A/w)%10;
                if(a[i][j]==0) x=i,y=j;
                w/=10;
            }
        }
    }
    int work2()           //将矩阵转化为数字              
    {
        int now=0;
        for(int i=1;i<=3;i++)
        {
            for(int j=1;j<=3;j++)
            {
                now=now*10+a[i][j];
            }
        }
        return now;
    }
    void bfs()
    {
        if(S==E) return ; //这里要特判一下,不然会TLE            
        state[S]=1;       //用1表示当前状态是正搜得到 
        state[E]=2;       //用2表示当前状态是反搜得到 
        ans[S]=0;         //初始状态不用搜索即可得到 
        ans[E]=0;         //最终状态不用搜索即可得到 
        q.push(S);        //这里将正搜反搜的两个队列压成一个,节省空间 
        q.push(E);
        while(!q.empty())
        {
            int now,cur;
            now=cur=q.front();  //cur表示即将要被扩展的状态 
            q.pop();
            work1(now);   //将数字转化为矩阵,并找出0的坐标 
            for(int i=0;i<4;i++)//向四种方向扩展(将0与四周的数字进行交换) 
            {
                int nx=x+dx[i];
                int ny=y+dy[i];
                if(nx<1||nx>3||ny<1||ny>3) continue;  //出界的情况不考虑 
                swap(a[x][y],a[nx][ny]);    //交换得到新状态 
                now=work2();                //将新状态转化成数字 
                if(state[now]==state[cur])  //如果新状态和当前状态同时被一种搜索(正搜或反搜一种)搜到了,说明这个状态已经搜过了不用再搜了 
                {
                    swap(a[x][y],a[nx][ny]);//此时九宫格的状态还是新状态,注意要换回来 
                    continue;
                } 
                if(state[now]+state[cur]==3)//如果新状态和当前状态分别被正搜和反搜搜到(1+2=3),那么就搜完了 
                {
                    Ans=ans[now]+ans[cur]+1;//注意要考虑上当前状态转移到新状态的步数,所以别忘了加一 
                    return ;
                }
                ans[now]=ans[cur]+1;        //转移步数 
                state[now]=state[cur];      //新状态由当前状态转移而来,那么它们一定被同一种搜索搜到 
                q.push(now);                //新状态入队,继续进行扩展 
                swap(a[x][y],a[nx][ny]);    //这里别忘了换回当前状态 
            }
        }
    }
    int main()
    {
        S=read();                           //输入初始状态     
        bfs();                              //双向bfs 
        printf("%d
    ",Ans);                 //输出答案 
        return 0;
    }

    萌新也是初探双向 $bfs$,如果您有任何疑问可以在评论区留言哦,我尽量一一解答,感谢您们的观看$qwq$。 

  • 相关阅读:
    重装系统后texstudio拼写检查不工作
    git bash使用端口转发连接服务器
    YCSB-mapkeeper
    编译thrift外篇-关于默认链接包-(使用mapkeeper运行leveldb成功)
    编译Thrift
    Could not resolve view with name 'sys/login' in servlet with name 'dispatcher'
    Eclipse创建一个Maven Web项目
    Maven安装配置
    使用Maven创建Web应用程序项目
    org.apache.jasper.JasperException: Unable to compile class for JSP:
  • 原文地址:https://www.cnblogs.com/xcg123/p/12678852.html
Copyright © 2011-2022 走看看