第四届蓝桥杯国赛——九宫重排
题目描述
如下图的九宫格中,放着 1 ~ 8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。 经过若干次移动,可以形成图 2 所示的局面。
我们把上图的局面记为:12345678.
把下图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出 -1。
输入格式
输入第一行包含九宫的初态,第二行包含九宫的终态。
输出格式
输出最少的步数,如果不存在方案,则输出 -1。
输入样例:
12345678.
123.46758
输出样例:
3
运行限制
最大运行时间:2s
最大运行内存: 256M
题目大意
从开始状态移动最少走多少步才能走到给定结束状态。
下图为模拟的样例:
题目解决思路
- 先将两种状态读入进来,
start
和end
。
for (int i = 0; i < 9; i ++ )
{
char c;
cin >> c;
start += c;
}
for (int i = 0; i < 9; i ++ )
{
char c;
cin >> c;
endd += c;
}
- 这道题目是道典型的求最短路径的题目,采用bfs的做法,我们直接使用一维来反计算二维坐标即
x=k/3
,y=k%3
,其中k
是二维坐标的点在一维坐标的下标。当且仅当状态变为终止状态时,退出宽搜算法,输出答案。
int bfs()
{
queue<string> q;
unordered_map<string, int> d;
q.push(start);
d[start] = 0;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
while (q.size())
{
string t = q.front();
q.pop();
int distance = d[t];
if(t == endd) return distance;
int k = t.find('.');
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 && b >= 0 && a < 3 && b < 3)
{
swap(t[a * 3 + b], t[k]);
if(!d.count(t))
{
d[t] = distance + 1;
q.push(t);
}
swap(t[a * 3 + b], t[k]);
}
}
}
return -1;
}
代码如下~
c++代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
#include <queue>
using namespace std;
string start, endd;
int bfs()
{
queue<string> q;//存储状态
unordered_map<string, int> d;//存储该状态下的距离
q.push(start);//将开始状态入队列
d[start] = 0;//开始状态距离为0
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};//定义上下左右四个向量
while (q.size())//当队列为空时,结束bfs算法
{
string t = q.front();//取出队头元素,命名为t状态
q.pop();
int distance = d[t];//t状态下的距离为distance
if(t == endd) return distance;///当t状态和终止状态相同时找到答案结束bfs,返回答案
int k = t.find('.');//找到t状态下空格在一维坐标下的位置
int x = k / 3, y = k % 3;//反算t状态下二维坐标下的位置(x,y)
for (int i = 0; i < 4; i ++ )//枚举上下左右四个向量
{
int a = x + dx[i], b = y + dy[i];//加上偏移量后点的坐标
if(a >= 0 && b >= 0 && a < 3 && b < 3)//如果没有越界
{
swap(t[a * 3 + b], t[k]);//交换一维坐标下的值
if(!d.count(t))//如果该状态并没有被遍历过则更新该状态的距离,并入队列
{
d[t] = distance + 1;
q.push(t);
}
swap(t[a * 3 + b], t[k]);//还原现场,因为还有剩余的向量并没有被枚举过
}
}
}
return -1;//如果没有找到的话,返回-1
}
int main()
{
cin.tie(0);//cin加速器,使用之后读入会很快
for (int i = 0; i < 9; i ++ )//读入开始状态
{
char c;
cin >> c;
start += c;
}
for (int i = 0; i < 9; i ++ )//读入终止状态
{
char c;
cin >> c;
endd += c;
}
cout << bfs();//输出答案
return 0;
}