宽搜:洛谷P1379 八数码难题 题解

我们先来看一下题目(可以去洛谷网站读题,如果题目已经读过了可以跳过)

题目

题目描述

在 3×3 的棋盘上,摆有八个棋子,每个棋子上标有 1 至 8 的某一数字。棋盘中留有一个空格,空格用 0 来表示。空格周围的棋子可以移到空格中。要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了使题目简单,设目标状态为 123804765),找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变。

输入格式

输入初始状态,一行九个数字,空格用 0 表示。

输出格式

只有一行,该行只有一个数字,表示从初始状态到目标状态需要的最少移动次数。保证测试数据中无特殊无法到达目标状态数据。

输入输出样例

输入 #1

283104765

输出 #1

4

说明/提示

样例解释

图中标有 0 的是空格。绿色格子是空格所在位置,橙色格子是下一步可以移动到空格的位置。如图所示,用四步可以达到目标状态。

并且可以证明,不存在更优的策略。

题目分析

别看题目是八数码难题,实际上一点都不难(自己光查错就查了很长时间)

这题要求我们找到一种最少步骤的移动方法,实现从初始布局到目标布局的转变,所以这道题最好用宽搜而不是用深搜

讲解

变量定义

int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};//从当前的位置到上下左右,横坐标和纵坐标要变的数值
string s1,s2;//s1为初始布局,s2为目标布局,即“123804765”
struct node//定义结构体
{
	string s;//布局(状态)
	int step;//到这个布局用了多少步
};//注意这里要加“;”号
queue<node>q;//定义结构体类型的队列
map<string,int> ma;//映射

每个变量的含义见代码里的批注

queue是队列,遵循“先进先出”的原则

map是映射,作用是标记这个状态有没有被搜过

注意:定义结构体类型的后面的那个大括号,后面别忘了加“;”号!!!(本蒟蒻就是在这里查了半天错)

1.主函数main

我们只需要输入初始布局,把"123804765"这个目标状态赋值给s2,再进入bfs就可以了

代码:

int main()
{
	int i,j,k;
	cin>>s1;
	s2="123804765";
	bfs();
 	return 0;
}

2.bfs(宽搜)

找到“0”(空格)的位置,然后将它与上下左右四个方向上的数进行交换,查找可能的情况,如果查找到某种情况是目标状态,因为是宽搜,所以保证查找到目标状态时一定是最少步骤,所以可以直接输出,跳出bfs,无需继续查找

代码:

void bfs()//宽搜
{
	q.push({s1,0});
	ma[s1]=1;//将初始状态进队,并标记这个状态已经被查找过了,避免重复查找
	while(q.size())
	{
		node t=q.front();//得到上一个状态
		q.pop();//弹出队头
		int w=t.s.find('0');//找到"0"在字符串的位置,即空格的位置
		int x=w/3,y=w%3;//x,y表示“0”的横坐标和纵坐标
		if(t.s==s2)//如果已经达到目标状态,则直接输出最少步骤,跳出bfs
		{
			printf("%d",t.step);//输出最少步骤
			return;//跳出bfs
		}
		for(int i=1;i<=4;i++)
		{
			int a=x+dx[i],b=y+dy[i];//a,b表示“0”的上下左右四个位置的横坐标和纵坐标
			if(a>=0&&a<=2&&b>=0&&b<=2)//判断是否越界
			{
				swap(t.s[a*3+b],t.s[w]);//交换“0”与被交换的位置上的数
				if(ma[t.s]==0)//如果这个状态还没有被搜过,则把这个状态进队
				{
					ma[t.s]=1;//标记这个状态为1,即已经被查找过了
					q.push({t.s,t.step+1});//把这个状态进队
				}
				swap(t.s[a*3+b],t.s[w]);//别忘了再交换回来,回到上一步,以便再查找下一种可能
			}
		}
	}
}

完整AC代码

#include <bits/stdc++.h>
using namespace std;
int dx[5]={0,-1,1,0,0},dy[5]={0,0,0,-1,1};//从当前的位置到上下左右,横坐标和纵坐标要变的数值
string s1,s2;//s1为初始布局,s2为目标布局,即“123804765”
struct node//定义结构体
{
	string s;//布局(状态)
	int step;//到这个布局用了多少步
};//注意这里要加“;”号
queue<node>q;//定义结构体类型的队列
map<string,int> ma;//映射
void bfs()//宽搜
{
	q.push({s1,0});
	ma[s1]=1;//将初始状态进队,并标记这个状态已经被查找过了,避免重复查找
	while(q.size())
	{
		node t=q.front();//得到上一个状态
		q.pop();//弹出队头
		int w=t.s.find('0');//找到"0"在字符串的位置,即空格的位置
		int x=w/3,y=w%3;//x,y表示“0”的横坐标和纵坐标
		if(t.s==s2)//如果已经达到目标状态,则直接输出最少步骤,跳出bfs
		{
			printf("%d",t.step);//输出最少步骤
			return;//跳出bfs
		}
		for(int i=1;i<=4;i++)
		{
			int a=x+dx[i],b=y+dy[i];//a,b表示“0”的上下左右四个位置的横坐标和纵坐标
			if(a>=0&&a<=2&&b>=0&&b<=2)//判断是否越界
			{
				swap(t.s[a*3+b],t.s[w]);//交换“0”与被交换的位置上的数
				if(ma[t.s]==0)//如果这个状态还没有被搜过,则把这个状态进队
				{
					ma[t.s]=1;//标记这个状态为1,即已经被查找过了
					q.push({t.s,t.step+1});//把这个状态进队
				}
				swap(t.s[a*3+b],t.s[w]);//别忘了再交换回来,回到上一步,以便再查找下一种可能
			}
		}
	}
}
int main()
{
	int i,j,k;
	cin>>s1;
	s2="123804765";
	bfs();
 	return 0;
}

后言

如果本篇题解有漏洞,欢迎大家来批斗本蒟蒻

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值