【双向BFS】九宫重排

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值