洛谷 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是个不错的选择。

posted @ 2018-06-28 09:23  Christopher_Yan  阅读(254)  评论(0编辑  收藏  举报