蓝桥杯 九宫重排

一、问题描述

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

二、输入格式

测试点1
12345678.
123.46758

测试点2
13524678.
46758123.

三、输出格式

测试点1答案
3

测试点2答案
22

四、题解

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

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

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

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

如果是在二维数组的时候,交换两个数组,我们可以用两个数组,分别是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 
#include 
#include 
#include 
#include 
#include 

using namespace std;

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


queue 

Q1; queue

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; }

你可能感兴趣的:(蓝桥杯,搜索)