• 洛谷 1379 八数码难题


    洛谷 1379 八数码难题

    八数码难题,一道经典的BFS题目(反正我也不会什么康托展开...)写完后,发现众多题解中并没有几篇双向BFS,于是就来发一波题解(尽管单向的BFS也能AC,但双向BFS明显要高效许多)。

    思路如下:

    首先我们可以将这个3x3的矩阵转化为一个九位数字,存入队列时也会方便很多,按方向尝试0周围的数字,判重记答案时可以使用map。然后就这样进行单向的BFS,accepted!

    重要优化:双向BFS

    双向BFS的使用要求之一就是知道终止状态,这道题目实在是在合适不过了。 这里可以将判重数组的值设为0,1,2,分别代表未访问过,顺序访问过,逆序访问过,当某个状态被顺序逆序都访问过时,那么这就是连接答案的那个状态。如果看到这里还不甚理解,不用着急,代码是比较清晰的。

    双向BFS满分代码:

    #include<bits/stdc++.h>
    #define ll long long int
    using namespace std;
    int n,g=123804765;
    short a[4][4],fx,fy,nx,ny;
    int dx[4]={1,-1,0,0};
    int dy[4]={0,0,1,-1}; //代表向四个方向移动
    queue<int> q;
    map<int,int> v;
    map<int,int> ans;
    void solve()
    {
        if(n==g)         //特判
        {
            printf("0");
            exit(0);
        }               
        q.push(n);      //起始状态与终止状态同时入队
        q.push(g);
        ans[n]=0;
        ans[g]=1;       
        v[g]=2;         //将两个方向标记成不同的数字
        v[n]=1;
        while(!q.empty())
        {
            ll now,cur=q.front();
            q.pop();
            now=cur;
            for(int i=3;i>=1;i--)
                for(int j=3;j>=1;j--)
                {
                    a[i][j]=now%10,now/=10;
                    if(a[i][j]==0) fx=i,fy=j;
                }
            for(int i=0;i<4;i++)
            {
                nx=fx+dx[i];
                ny=fy+dy[i];
                if(nx<1 || nx>3 || ny<1 || ny>3) continue;
                swap(a[fx][fy],a[nx][ny]);
                now=0;
                for(int p=1;p<=3;p++)
                    for(int j=1;j<=3;j++)
                        now=now*10+a[p][j]; //数字转矩阵
                if(v[now]==v[cur]) 
                {
                    swap(a[fx][fy],a[nx][ny]); //一定要先换回来再跳过
                    continue;
                }
                if(v[now]+v[cur]==3)        //说明新延伸出的点已被另一方向访问过
                {
                    printf("%d",ans[cur]+ans[now]);//两方向步数和即为总步数
                    exit(0);
                }
                ans[now]=ans[cur]+1;
                v[now]=v[cur];              //与上一状态的方向保持一致
                q.push(now);
                swap(a[fx][fy],a[nx][ny]); //不要忘记将还回来
            }   
        }
    }
    int main()
    {
        scanf("%d",&n);
        solve();
    }

    最后说一下这个双向的效率有多高:

    单向BFS:8388ms.

    双向BFS:228ms.

    这里列举了两组数据,科学准确的说明了....

    所以我认为这道题目写双向BFS是个不错的选择。

  • 相关阅读:
    [android] 帧布局
    [android] 表格布局和绝对布局
    使用LVS实现负载均衡原理及安装配置详解
    学习Docker之Dockerfile的命令
    使用docker-compose部署nginx
    CentOS Bash 命令补全增强软件包 bash-completion
    “三次握手,四次挥手”你真的懂吗?
    0777 0的意思
    linux文件或目录权限修改后如何恢复(备份了权限就能恢复)
    centos7进入单用户模式
  • 原文地址:https://www.cnblogs.com/yanyiming10243247/p/9237052.html
Copyright © 2020-2023  润新知