题目 1426: [蓝桥杯][历届试题]九宫重排
链接:C语言网——九宫重排
题目描述
如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着。与空格子相邻的格子中的卡片可以移动到空格中。经过若干次移动,可以形成第二个图所示的局面。
我们把第一个图的局面记为:12345678.
把第二个图的局面记为:123.46758
显然是按从上到下,从左到右的顺序记录数字,空格记为句点。
本题目的任务是已知九宫的初态和终态,求最少经过多少步的移动可以到达。如果无论多少步都无法到达,则输出-1。
输入
输入第一行包含九宫的初态,第二行包含九宫的终态。
输出
输出最少的步数,如果不存在方案,则输出-1。
样例输入
12345678.
123.46758
样例输出
3
用到库函数:map,queue
用到方法:双向BFS
刚学了这两个库函数,运用不是很熟练,求谅解
思路:双向BFS
- 用字符串来表示9宫格的内容,然后用map把每个用过的string标记并记录步数
- 将字符串转化为九宫格向4个方向(上下左右)探索是否越界,若没有越界,则将字符串的
.
与相应位置交换 - 判重,判断是否相交,入队
代码有注释哦
代码
#include<iostream>
#include<queue>
#include<map>
using namespace std;
map<string,int>dis,vis;
//dis记录步数 vis中的 1为从开始遍历的 ,2为从结尾遍历的
//若首位相接则两个vis相加等于3
string s,e;
int dir1[4][2]={{-1,0},{0,1},{1,0},{0,-1}};//九宫格方向 上下左右
int dir2[4]={-3,1,3,-1};//字符串改变.位置(九宫格判断是否越界后)
int Found(string a);//找到.的位置
bool IsOver(int x,int y);//判断是否超出九宫格
string Change(string str,int b);//九宫格的. 的位置交换 (用string表示)
void bfs();
int main()
{
cin >> s>>e;
bfs();
}
int Found(string a)//找到.的位置
{
for(int i=0;i<a.size();i++)
{
if(a[i]=='.')
return i;
}
}
bool IsOver(int x,int y)//判断是否超出九宫格
{
if(x<0||x>=3||y<0||y>=3)
return false;
return true;
}
string Change(string str,int b)//九宫格的. 的位置交换 (用string表示)
{
char temp;
temp=str[b];
str[Found(str)]=temp;
str[b]='.';
return str;
}
void bfs()
{
if(s==e)
{
cout << 0<<endl;
return;
}
queue<string>q; //队列
//将开始和结尾同时放入队列 (同时遍历)
q.push(s);
q.push(e);
dis[s]=0;
dis[e]=1;
vis[s]=1;
vis[e]=2;
int judge=0;//判断是否相交 来退出循环
while(!q.empty())
{
string nt=q.front();//得到第一个元素命名为 nt
q.pop();//第一个元素出队
for(int i=0;i<4;i++)//以第一个元素为中心 上下左右去探索
{
string nq;//试探子
int x,y; //得到 nt 的九宫格坐标
x=Found(nt)/3;
y=Found(nt)%3;
if(IsOver(x+dir1[i][0],y+dir1[i][1]))//判断是否越界 若没有越界
{
nq=Change(nt,Found(nt)+dir2[i]);//则将nt的字符串的.的位置与相应位置互换给nq
if(vis[nq]+vis[nt]==3)//两个vis相加=3 则相遇
{
cout << dis[nq]+dis[nt] << endl;
judge=1;
break;
}
else if(vis[nq]==0)//为了不重复遍历同一个地方
{
vis[nq]=vis[nt];//从哪里开始和上一个元素的vis相同(1或2)
dis[nq]=dis[nt]+1;
q.push(nq);
}
}
}
if(judge)
{
break;
}
}
if(!judge)
{
cout << -1<<endl;
}
}