BFS:八数码问题求解

八数码原题

剖析一下BFS

        BFS算法是一种图遍历算法,它从起点开始,逐层扩展搜索范围,直到找到目标节点为止。        

        BFS算法一般选择队列作为节点存储的数据结构,我们将搜索目标节点的问题抽象为寻找目标状态,那么队列存储的对象就是每一种状态。

        对于状态的含义与变化过程,BFS算法如下要求(为了讲解得更加透彻,举走迷宫问题为例):

  1. 初始以及其拓展出开的状态都要存储在队列中。在走迷宫问题中,队列q存储已走过的点 ,点代表位置状态,基于一个点可以拓展出它四周的点;
  2. 问题的求解必须有初始状态最终状态。在走迷宫问题中,起点(0,0)便是初始状态,而终点(n,n)是最终状态;
  3. 问题的状态次数是有限的已出现的状态一般需要被记录下来。在走迷宫问题中,dis[i][j]表示从起点到达点(i,j)的距离。当dis的所有元素被初始化为0时,如果dis[i][j]非零时,就说明点(i,j)已被记录过;
  4. 当前状态preState可以拓展出其他状态State,如果State已经出现过或者不符合要求,那么该状态无法加入队列中.

八数码问题的求解 

问题描述

        八数码,在3×3的方格棋盘上,摆放着1到8这八个数码,有1个方格放置字符x,其初始状态如图所示,要求对字符x执行x左移、x右移、x上移和x下移这四个操作使得棋盘从初始状态到目标状态。

        147ac6bb7d3b4fd7ab401c398919f979.png

        基于上述状态能够拓展出如下四种状态:

 

7af3caa860a84e0dbf6fdf8ee5809ba5.png

         八数码问题要求是,对字符x进行若干次唯一操作,得到目标状态并且求算操作次数: 

9ea05a3f65d745cfa077648e36522153.png

 求解思路

  1. 每一个矩阵的里面的元素能够用一个字符串来存储,例如存储最终状态string s = "12345678x";
  2. 本问题借助state结构体存储每一种状态,state的分量为:s,pos,step.其中,s代表该状态对应的字符串,pos代表x在s字符串中的位置,step代表本状态由初始转台经过了step次操作得来;
  3. 定义一个map<string,bool>st映射,记录该字符串(即新拓展出来的状态)曾经是否出现过,即已出现的状态需要被记录下来;
  4. 当前状态preState包含三个分量{s,pos,step},根据pos与s值,拓展出其他至多四种状态,具体实现将代码的genOtherState函数.

        好啦,大功告成~~👌👌👌其他细节部分见代码后,也许会有更加深刻的体会(代码有详细注释,所谓优秀的代码本身就是学习文档!!!)

代码实现

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
#include<map>
#include<queue>
using namespace std;//	come from Acwing//	记录状态
struct state {string s;int pos;	//	x的位置int step;	//	step次交换
};string str;
map<string, bool>st;	//	记录某个状态是否曾出现
queue<state>q;	//	状态队列//	产生其他状态
void genOtherState(const state& sta) {string s;state t;//	判断是否能够交换x与它上面字符的位置if (sta.pos - 3 >= 0) {//	交换两个字符的位置s = sta.s;swap(s[sta.pos], s[sta.pos - 3]);if (!st[s]) {q.push(state{ s,sta.pos - 3,sta.step + 1 });st[s] = true;}}//	判断是否能够交换x与它下面字符的位置if (sta.pos + 3 <= 8) {s = sta.s;swap(s[sta.pos], s[sta.pos + 3]);if (!st[s]) {q.push(state{ s,sta.pos + 3,sta.step + 1 });st[s] = true;}}// 判断是否能够交换x与它右边字符的位置if (sta.pos % 3<=1) {s = sta.s;swap(s[sta.pos], s[sta.pos + 1]);if (!st[s]) {q.push(state{ s,sta.pos + 1,sta.step + 1 });st[s] = true;}}// 判断是否能够交换x与它左边字符的位置if (sta.pos % 3 >= 1) {s = sta.s;swap(s[sta.pos], s[sta.pos - 1]);if (!st[s]) {q.push(state{ s,sta.pos - 1,sta.step + 1 });st[s] = true;}}
}int bfs(int pos) {string target = "12345678x";	//	目标状态// 初始化state init = state{ str,pos,0 };q.push(init);st[str] = true;while (q.size()) {auto t = q.front();	//	取出队头状态进行拓展q.pop();if (t.s == target) {return t.step;}//	当前状态拓展出其余状态genOtherState(t);}return -1;
}int main() {int cnt = 9;int pos = 0;//	输入for (int i = 0;i <= 8;i++) {char a;cin >> a;if (a == 'x') {pos = i;}str += a;}int res = bfs(pos);cout << res << endl;return 0;
}

 总结

        本博客先解释了BFS的存储队列节点的抽象含义,将每一个节点看作一种状态,并从状态存储、状态记录、状态拓展等角度解答了BFS算法如何解决遍历问题。

        紧接着,我们借助BFS算法的状态处理方法给出了八数码问题的求解思路。我们以字符串存储了八数码的每一种状态,每一种状态记录{s,pos,step}三个分量,借助st映射记录新拓展出的状态,并于代码中给出状态拓展的方法。

        实际上,八数码问题只是抽象BFS问题的一种实例化,当我们判断一个问题是否属于BFS问题时,需要判断问题是否存在初始状态与最终状态?每一种状态如何存储,有哪些分量?如何记录每一种状态?每一种状态拓展出其他状态的方式是否是规律的且有限的?掌握了如上的思考方式,相信你能够在下一次遇到或判断一个问题是否属于BFS问题时,你能够更加游刃有余!!!

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/228639.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue3 reative回显问题

1. reactive 在做项目的时候通常会遇到这种情况&#xff0c;比如我们有一个 Table 显示数据&#xff0c;添加 Table 数据的时候使用 dialog 弹出&#xff0c;在里面填写字段然后添加。 在 vue3 中&#xff0c;对于对象的响应式定义推荐使用 reactive &#xff0c;那么可以写入…

运筹学经典问题(二):最短路问题

问题描述 给定一个图&#xff08;有向图或无向图&#xff09; G ( V , E ) G (V, E) G(V,E)&#xff0c; V V V是图中点的集合&#xff0c; E E E是图中边的集合&#xff0c;图中每条边 ( i , j ) ∈ E (i, j) \in E (i,j)∈E都对应一个权重 c i j c_{ij} cij​&#xff08;…

Android取消深色适配

从Android10&#xff08;API 29&#xff09;开始&#xff0c;在原有的主题适配的基础上&#xff0c;Google开始提供了Force Dark机制&#xff0c;在系统底层直接对颜色和图片进行转换处理&#xff0c;原生支持深色模式。当系统设置深色主题背景或者进入省电模式情况下会进入深色…

2023年烟花爆竹经营单位主要负责人证模拟考试题库及烟花爆竹经营单位主要负责人理论考试试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2023年烟花爆竹经营单位主要负责人证模拟考试题库及烟花爆竹经营单位主要负责人理论考试试题是由安全生产模拟考试一点通提供&#xff0c;烟花爆竹经营单位主要负责人证模拟考试题库是根据烟花爆竹经营单位主要负责人…

C++ STL容器概览

容器概览 容器分类 顺序容器提供对元素&#xff08;半开&#xff09;序列的访问。 vectorlistforward_listdeque 关联容器提供基于关键字的关联查询。 有序关联容器&#xff1a;通常用平衡二叉树&#xff08;红黑树&#xff09;实现。 mapmultimapsetmultiset 无序关联容器&a…

NestJS使用gRPC实现微服务通信

代码仓库地址&#xff1a;https://github.com/zeng-jc/rpc-grpc-practice 1.1 基本概念 gRPC 基于 Protocol Buffers&#xff08;protobuf&#xff09;作为接口定义语言&#xff08;IDL&#xff09;&#xff0c;意味着你可以使用 protobuf 来定义你的服务接口&#xff0c;gRP…

【HDFS面试】HDFS面试题答案

题目 HDFS文件写入和读取流程 HDFS组成架构 介绍下HDFS&#xff0c;说下HDFS优缺点&#xff0c;以及使用场景 HDFS作用 HDFS的容错机制 HDFS的存储机制 HDFS的副本机制 HDFS的常见数据格式&#xff0c;列式存储格式和行存储格式异同点&#xff0c;列式存储优点有哪些? …

【环境搭建】Win10下安装Docker

下载地址 Docker Windows 桌面版下载地址 各镜像下载地址 可能遇到的问题 安装后一直显示以下文字 Starting the Docker Engine… Docker Engine is the underlying technology that runs containers 请尝试使用此方法&#xff1a;https://zhuanlan.zhihu.com/p/667495068

RGB颜色表示法(RGBA解释) 以及常见的色调

RGB&#xff1a;代表red&#xff0c;green&#xff0c;blue。即用这三个色调表示所有颜色。 表示方式如&#xff1a;&#xff08;255,255,255&#xff09;白色、&#xff08;0,0,0&#xff09;黑色 改变三个不同的数值可以得到不同的颜色&#xff0c;数值取值范围为0-255&#…

【shell脚本实战案例】awk实现行转列数据变换

问题背景&#xff1a; awk&#xff08;“Aho, Weinberger, and-Kernighan”&#xff09; 是一种文本处理工具&#xff0c;用于从输入文件中提取并输出指定的信息。它以行为单位读取文件&#xff0c;并根据用户定义的模式和操作来处理每一行数据。 awk命令是一种强大的编程语…

设计模式——模板方法模式

引言 模板方法模式是一种行为设计模式&#xff0c; 它在超类中定义了一个算法的框架&#xff0c; 允许子类在不修改结构的情况下重写算法的特定步骤。 问题 假如你正在开发一款分析公司文档的数据挖掘程序。 用户需要向程序输入各种格式 &#xff08;PDF、 DOC 或 CSV&#…

Ubuntu 常用命令之 cp 命令用法介绍

cp命令在Ubuntu系统中用于复制文件或目录。它的基本格式是cp [选项] 源文件或目录 目标文件或目录。 以下是一些常用的cp命令选项 -i&#xff1a;在覆盖目标文件之前将给出提示。-r或-R&#xff1a;递归复制&#xff0c;用于目录的复制操作。-v&#xff1a;详细模式&#xff…

2023-12-12 AIGC-AI工具的基本工作原理

摘要: 2023-12-12 AIGC-AI工具的基本工作原理 AI工具的基本工作原理 AI工具的基本工作原理涉及到一系列复杂的技术和算法。这些原理可以根据不同类型的AI工具进行概括&#xff0c;包括机器学习、自然语言处理、图像识别等。以下是一些关键的AI工具及其工作原理的概述&#xff…

对于实例控制,枚举类型优先于readResolve

实例控制是指控制类实例的创建和使用过程&#xff0c;而 readResolve 方法是 Serializable 接口中的一个特殊方法&#xff0c;用于在反序列化时控制对象的实例。在一些情况下&#xff0c;使用枚举类型可以更优雅地实现实例控制&#xff0c;而不需要依赖 readResolve 方法。 下…

shell编程-uniq命令详解(超详细)

文章目录 一、引言二、命令格式和选项三、示例用法四、注意事项和常见问题五、扩展应用六、总结七、参考文献 一、引言 本文将介绍Unix/Linux系统中的uniq命令&#xff0c;该命令用于从输入中删除重复的行&#xff0c;并可进行排序和统计操作。uniq命令在处理文本文件时非常有…

网络基础(十二):ACL与NAT

目录 一、ACL 1、ACL的概述 2、ACL的分类 3、ACL的应用 4、ACL的组成和基本原理 ​编辑 5、ACL的配置 5.1配置基本ACL 5.2配置高级ACL 二、NAT 1、NAT的概述 2、NAT的分类 3、NAT的工作原理 4、静态NAT的配置 5、动态NAT的配置 6、NAPT&#xff08;端口映射&am…

查询某个类是在哪个JAR的什么版本开始出现的方法

背景 我们在依赖第三方JAR时&#xff0c;同时也会间接的依赖第三方JAR引用的依赖&#xff0c;而当我们项目中某个依赖的版本与第三方JAR依赖的版本不一致时&#xff0c;可能会导致第三方JAR的在运行时无法找到某些方法或类&#xff0c;从而无法正常使用。 如我正在开发的一个…

流程引擎相关资料

最近调研流程引擎相关知识&#xff0c;BPMN规范和流程引擎相关知识无法避开&#xff0c;以及市面上比较多的流程引擎产品。 BPMN2.0 基本形状 流对象&#xff08;Flow Objects&#xff09;&#xff0c;流对象是定义业务流程的主要图形元素。它进一步细分为三个类别&#xff0…

代码随想录算法训练营

Day 01 | 704. 二分查找、27. 移除元素 今日学习的文章链接和视频链接 自己看到题目的第一想法 看完代码随想录之后的想法 自己实现过程中遇到哪些困难 今日收获&#xff0c;记录一下自己的学习时长 Day 02 | 977.有序数组的平方 &#xff0c;209.长度最小的子数组 &#xff…

运行时类的应用

创建运行时类的对象 例&#xff1a; 创建运行时类的Class类对象。 Class<Person> clazz Person.class&#xff1b; newInstance(&#xff09;:调用此方法&#xff0c;创建对应的运行时类的对象。内部调用了运行时类的空参构造器。 Person p clazz.newInstance(); …