AcWing、845. 八数码

133 阅读2分钟

本文已参与[新人创作礼]活动,一起开启掘金创作之路。

logo.png

题目描述

845. 八数码 - AcWing题库

在一个 3×3 的网格中,1∼8 这 8 个数字和一个 x 恰好不重不漏地分布在这 3×3 的网格中。

例如:

1 2 3
x 4 6
7 5 8

在游戏过程中,可以把 x 与其上、下、左、右四个方向之一的数字交换(如果存在)。

我们的目的是通过交换,使得网格变为如下排列(称为正确排列):

1 2 3
4 5 6
7 8 x

例如,示例中图形就可以通过让 x 先后与右、下、右三个方向的数字交换成功得到正确排列。

交换过程如下:

1 2 3   1 2 3   1 2 3   1 2 3
x 4 6   4 x 6   4 5 6   4 5 6
7 5 8   7 5 8   7 x 8   7 8 x

现在,给你一个初始网格,请你求出得到正确排列至少需要进行多少次交换。

输入格式

输入占一行,将 3×3 的初始网格描绘出来。

例如,如果初始网格如下所示:

1 2 3 
x 4 6 
7 5 8 

则输入为:1 2 3 x 4 6 7 5 8

输出格式

输出占一行,包含一个整数,表示最少交换次数。

如果不存在解决方案,则输出 −1−1。

输入样例:

2  3  4  1  5  x  7  6  8

输出样例

19

问题解析

每次在矩阵中找到x的位置,把它和上下左右四个位置的数都交换一下(4种情况)比如题目所给的情况,第一次交换后就变成:

x 2 3     1 2 3     1 2 3 
  
1 4 6     4 x 6     7 4 6  

7 5 8     7 5 8     x 5 8

还有一种情况因为越界了所以不考虑,给最初的矩阵赋一个权值0,之后每有一次操作,权值都+1,判断当矩阵变为要求的情况时,返回当前的权值,这个权值就是最少的步数。如果列举所有情况任然没有要求的那种,就返回-1。

AC代码

#include<iostream>
using namespace std;
#include<unordered_map>
#include<queue>
#include<algorithm>


int bfs(string str)
{
    int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
    unordered_map<string,int>mymap;
    queue<string>que;
    que.push(str);
    string end="12345678x";
    mymap[str]=0;
    while(que.size())
    {
        string t=que.front();
        int ans=mymap[t];
        if(t==end)return ans;
        que.pop();
        int k=t.find('x');
        int x=k/3,y=k%3;
        for(int i=0;i<4;i++)
        {
            int a=x+dx[i],b=y+dy[i];
            if(a>=0&&a<3&&b>=0&&b<3)
            {
                swap(t[k],t[a*3+b]);
                if(!mymap.count(t))
                {
                    mymap[t]=ans+1;
                    que.push(t);
                }
                swap(t[k],t[a*3+b]);
            }
        }
    }
    return -1;
}

int main()
{
    string str;
    char c;
    for(int i=0;i<9;i++)
    {
         cin>>c;
         str+=c;
    }
    cout<<bfs(str)<<endl;
    return 0;
}