一、问题描述

如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
蓝桥杯 九宫重排
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。

二、输入格式

测试点1
12345678.
123.46758

测试点2
13524678.
46758123.

三、输出格式

测试点1答案
3

测试点2答案
22

四、题解

一般求搜索题目求最短路径都是用bfs来实现的。但是这道题我想着用双向广度优先搜索来实现。

双向广度搜索,就是比广度优先搜索再多一个搜索,这个搜索是从终点向起点搜索。那么这样子我们就有两个搜索了,一个从起点向终点搜索,一个从终点在起点搜索,那么当两个搜索都找到同一个子状态时,搜索就结束了。这样子就可以提高搜索的效率了。

现在我用画图来模拟一下搜索过程(部分过程)。
蓝桥杯 九宫重排
那么当数据规模很大时,我们采用双向搜索就可以提高效率,降低时间复杂度了。

这道题还有一个可优化的点,就是将二位数组压成一位数组,如下所示。
蓝桥杯 九宫重排
那么如果将二位数组转换成一维数组,在交换相邻那么数值,要怎么表示呢?

如果是在二维数组的时候,交换两个数组,我们可以用两个数组,分别是dx,dy。
dx[]={0,0,1,-1}; dy[]={1,-1,0,0};通过这两个数组能够实现当前元素同上下左右四个方向进行交换

那么,当压缩成一位数组的时候,我们同样可以用一个方向数组dir。这个dir数组应该这样设计
dir={1,-1,3,-3},其中1,-1,代表原本二维数组向左向右。3,-3代表原本二维数组向上向下。

然后我们还需要创建两个map,分别来存储正向搜索和反向搜索找到的子状态,当这两个map有相同子状态时,那么我们程序就结束了,直接将正向搜索的步数和反向搜索的步数相加。

五、代码实现

#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <queue>
#include <map>

using namespace std;

map <string, int> M1;
map <string, int> M2;
typedef pair <string, int> P;
int dir[4] = {1, -1, 3, -3};
string s, e;


queue <P> Q1;
queue <P> Q2;


bool judge(int x){
    if(x < 0 || x > 8)
        return false;
    else
        return true;
}


int bfs(){
    P p;
    p.first = s;
    p.second = 0;
    Q1.push(p);
    p.first = e;
    p.second = 0;
    Q2.push(p);

    while(!Q1.empty() && !Q2.empty()){

        if(!Q1.empty()){
            p = Q1.front();
            Q1.pop();
            string str = p.first;
            int step = p.second;
            int index = str.find('.');
            for(int i = 0; i < 4; ++ i){
                int curIndex = index + dir[i];
                string newStr = str;
                char ch = newStr[index];
                newStr[index] = newStr[curIndex];
                newStr[curIndex] = ch;
                int newStep = step + 1;
                if((i == 0 && (index == 2 || index == 5))||(i == 1 && (index == 3 || index == 6)))
                    continue;
                if(judge(curIndex)){
                    if(M1[newStr])
                        continue;
                    M1[newStr] = newStep;
                    if(M2[newStr])
                        return M1[newStr] + M2[newStr];
                    P next;
                    next.first = newStr;
                    next.second = newStep;
                    Q1.push(next);
                }
            }
        }

        if(!Q2.empty()){
            p = Q2.front();
            Q2.pop();
            string str = p.first;
            int step = p.second;
            int index = str.find('.');
            for(int i = 0; i < 4; ++ i){
                int curIndex = index + dir[i];
                string newStr = str;
                char ch = newStr[index];
                newStr[index] = newStr[curIndex];
                newStr[curIndex] = ch;
                int newStep = step + 1;
                if((i == 0 && (index == 2 || index == 5))||(i == 1 && (index == 3 || index == 6)))
                    continue;
                if(judge(curIndex)){
                    if(M2[newStr])
                        continue;
                    M2[newStr] = newStep;
                    if(M1[newStr])
                        return M1[newStr] + M2[newStr];
                    P next;
                    next.first = newStr;
                    next.second = newStep;
                    Q2.push(next);
                }
            }
        }
    }
    return -1;
}
int main()
{
    int ans;
    cin >> s >> e;
    M1[s] = 0;
    M2[s] = 0;

    ans = bfs();
    if(ans == -1)
        cout << "-1" << endl;
    else
        cout << ans << endl;
    return 0;
}


相关文章:

  • 2021-07-27
  • 2021-07-28
  • 2021-05-16
  • 2021-06-01
  • 2021-12-26
  • 2021-06-11
  • 2022-12-23
  • 2021-04-17
猜你喜欢
  • 2022-01-28
  • 2022-12-23
  • 2021-11-06
  • 2021-07-09
  • 2021-07-24
  • 2022-12-23
相关资源
相似解决方案