以八数码问题为例实现A*算法的求解(未完结)

八数码: 

在一个 3×3 的网格中,1∼8 这 8 个数字和一个 x 恰好不重不漏地分布在这 3×3 的网格中。

例如:

1 2 3
x 4 6
7 5 8

在游戏过程中,可以把 x 与其上、下、左、右四个方向之一的数字交换(如果存在)。

我们的目的是通过交换,使得网格变为如下排列(称为正确排列):

1 2 3
4 5 6
7 8 x

例如,示例中图形就可以通过让 x 先后与右、下、右三个方向的数字交换成功得到正确排列。

交换过程如下:

1 2 3   1 2 3   1 2 3   1 2 3
x 4 6   4 x 6   4 5 6   4 5 6
7 5 8   7 5 8   7 x 8   7 8 x

现在,给你一个初始网格,请你求出得到正确排列至少需要进行多少次交换。

输入格式

输入占一行,将 3×3 的初始网格描绘出来。

例如,如果初始网格如下所示:

1 2 3 
x 4 6 
7 5 8 

则输入为:1 2 3 x 4 6 7 5 8

输出格式

输出占一行,包含一个整数,表示最少交换次数。

如果不存在解决方案,则输出 −1

输入样例:
2 3 4 1 5 x 7 6 8
输出样例
19

使用BFS求解思路:

题目要求的是3×3的矩阵八个数字,首先给一个起始状态start,然后要求通过算法,得到题目给的最终状态end。并且要求是最优解,即最短路径。

由此我们可以使用BFS即广度优先算法来解决此类问题,广度优先是层次遍历,每次通过遍历空格位置向上下左右四个方向交换,可得到四个不同的状态(边界可能小于4)以及与初始状态变化距离。

求解存在的问题:用什么数据结构来存储,该如何表示每次变化的状态,该如何记录每次状态距离初始状态的距离。

我们通过队列来记录层次遍历时每层的状态,每一层的共性就是移动距离相同。如图所示:

BFS

由于向左时越界所以跳过向左,由图所示,当前一共有三个状态,并且距离初始状态为1,与end状态比较不相等。

通过上面的解释,我们可以发现,使用队列来记录每次改变的状态最合适,因为队列可以按照层次遍历的顺序来存储状态,可以记录路径和搜索的顺序,并且可以帮助我们避免重复访问。然后,使用哈希表来存储每个状态对应的距离,每次要存储一次距离时,判断哈希表中是否存在当前要存储的状态,然后通过刚刚从队列中取出的状态距离加1即当前状态距离。

每次从队列中获取一个状态都要和最终状态比较,如果相等,返回hash表中对应的距离。否则通过改变空格位置来获取每次状态。如果遍历完所有的状态都没有,返回-1.

这里以JAVA为例,使用BFS算法,展示代码:

import java.sql.Statement;
import java.util.*;class Main {static int dx[] = {1, 0, -1, 0};static int dy[] = {0, -1, 0, 1};//空格位置的上下左右移动public static void main(String[] args) {Scanner cin = new Scanner(System.in);String start = new String();for (int i = 0; i < 9; i++) {char c;c = cin.next().charAt(0);start += c;}System.out.println(bfs(start));}private static int bfs(String start) {String end = new String();end = "12345678x";Queue<String> queue = new LinkedList<>();//存储状态Map<String, Integer> map = new HashMap<>();//每个状态到起点的位置queue.add(start);map.put(start, 0);while (!queue.isEmpty()) {String s = queue.poll();if (s.equals(end)) return map.get(s);int dist = map.get(s);int k = s.indexOf("x");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 && a < 3 && b >= 0 && b < 3) {String st = new String(swap(s.toCharArray(), k, a * 3 + b));if (map.get(st) == null) {map.put(st, dist + 1);queue.add(st);}st = new String(swap(s.toCharArray(), k, a * 3 + b));}}}return -1;}private static char[] swap(char[] chars, int k, int i) {char temp = chars[k];chars[k] = chars[i];chars[i] = temp;return chars;}
}

C++代码:

#include <algorithm>
#include <iostream>
#include <unordered_map>
#include <queue>
using namespace std;
int bfs(string s)
{queue<string>q;unordered_map<string,int>d;q.push(s);d[s]=0;string end="12345678x";int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};while(!q.empty()){string t=q.front();q.pop();if(t==end)return d[t];int distant=d[t];int k=t.find('x');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&&a<3&&b>=0&&b<3){	swap(t[k],t[a*3+b]);if(!d.count(t)){d[t]=distant+1;	q.push(t);}swap(t[k],t[a*3+b]);}}}return -1;
}
int main()
{string s;for(int i=0;i<9;i++){char a;cin>>a;s+=a;}cout<<bfs(s);return 0;
}

 在广度优先遍历算法中,我们发现在找到最终答案之前它遍历了所有状态的八数码(盲目式搜索),对于有明确终点的问题来说,其实可以优先考虑具有较小估计代价的状态来进行搜索以尽快找到解决方案。

 A*算法:

        A*算法(A-star algorithm)是一种启发式搜索算法,常用于解决图形和网络中的最短路径问题。该算法在已知节点之间的连接关系以及每个节点的估计成本(启发函数)的基础上,通过遍历节点来找到从起点到目标节点的最优路径。

        A*算法结合了Dijkstra算法和贪婪最佳优先搜索算法的特点,它维护两个值:g值和h值。其中g值表示起点到当前节点的实际代价,h值表示当前节点到目标节点的预计代价。通过合理选择启发函数,A*算法能够高效地找到最佳路径。

        A*算法使用一个优先队列来存储待探索的节点,并根据f值(f = g + h)的大小进行排序。在每一次迭代中,它选择f值最小的节点进行探索,计算其邻居节点的g值和h值,并更新优先队列。当从队列中选出的节点为目标节点时,路径被找到。

        A*算法在计算资源允许的情况下,通常能够找到最短路径。然而,如果启发函数不准确或者图形/网络过于复杂,A*算法可能会陷入局部最优解并无法找到全局最优解。

A*算法通过下面这个函数来计算每个节点的优先级。

其中:

  • f(n)是节点n的综合优先级。当我们选择下一个要遍历的节点时,我们总会选取综合优先级最高(值最小)的节点。
  • g(n) 是节点n距离起点的代价。
  • h(n)是节点n距离终点的预计代价,这也就是A*算法的启发函数。关于启发函数我们在下面详细讲解。

A*算法在运算过程中,每次从优先队列中选取f(n)值最小(优先级最高)的节点作为下一个待遍历的节点。

另外,A*算法使用两个集合来表示待遍历的节点,与已经遍历过的节点,这通常称之为open_setclose_set

A*算法解决八数码问题:

1. 定义状态表示:将八数码问题中的每个状态表示为一个3x3的矩阵,空白格用0表示。例如,初始状态为:

1 2 3 
x 4 6 
7 5 8 


2. 定义启发函数:根据当前状态和目标状态之间的差异,设计一个启发函数来估计从当前状态到目标状态的代价。

3. 实现A*算法:按照以下步骤实现A*算法来解决八数码问题

算法流程图

程序设计语言编写程序,实现算法; 

运行程序并对照分析不同估价函数对A*算法性能的影响。

      

总结

A*算法和广度优先搜索(BFS)都可以用于解决八数码问题,但它们之间存在一些重要的区别。

1. 目标导向性:
    A*算法是一种启发式搜索算法,它使用一个启发函数来估计当前状态到达目标状态的代价。它通过优先考虑具有较小估计代价的状态来进行搜索,以尽快找到解决方案。

   广度优先搜索则是一种朴素的无信息搜索方法,它按照层次遍历的方式搜索问题的解空间,逐渐扩展搜索树,直到找到目标状态为止。BFS不考虑每个状态的代价,只关注解的深度。

2. 内存消耗:
    A*算法通常需要维护一个优先队列来存储待扩展的状态,该队列的大小与搜索过程中生成的状态数量成正比。因此,A*算法可能会占用更多的内存空间。

    广度优先搜索也需要存储搜索树中所有已生成的状态,但不需要额外的优先队列。BFS在搜索空间中逐层扩展,可能会占用较大的内存空间,尤其是当搜索树的分支因子较大时。

3. 时间复杂度:
    A*算法的时间复杂度取决于启发函数的质量。在最坏情况下,A*算法的时间复杂度与状态空间的大小成指数关系。

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

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

相关文章

(11月4日)GBASE南大通用 x openGauss Meetup,欢迎报名

由openGauss社区、天津南大通用数据技术股份有限公司主办&#xff0c;伟仕佳杰科技有限公司、神州数码&#xff08;中国&#xff09;有限公司协办的“GBASE南大通用 x openGauss Meetup”活动将于2023年11月4日&#xff08;周六&#xff09;在合肥市高新区云飞路66号天源迪科科…

3DEXPERIENCE云端项目管理小工具--Project Planner项目策划者角色

云端3DEXPERIENCE平台提供了一个协作环境&#xff0c;使企业和个人能够以全新的方式实现创新。它将人员、创意、数据和解决方案连接到一个始终在线且可用的协作和交互环境中&#xff0c;可以帮助您的企业提高执行力、生产率并加速创新。 3DEXPERIENCE中的Project Planner项目策…

BUUCTF 后门查杀 1

BUUCTF:https://buuoj.cn/challenges 题目描述&#xff1a; 小白的网站被小黑攻击了&#xff0c;并且上传了Webshell&#xff0c;你能帮小白找到这个后门么&#xff1f;(Webshell中的密码(md5)即为答案)。 密文&#xff1a; 下载附件&#xff0c;解压得到一个网站文件夹。 解…

Nginx搭载负载均衡及前端项目部署

目录 ​编辑 一.Nginx安装 1.安装所需依赖 2.下载并解压Nginx安装包 3.安装nginx 4.启动Nginx服务 二.Tomcat负载均衡 1.准备环境 1.1 准备两个Tomcat 1.2 修改端口号 1.3 配置Nginx服务器集群 2.效果展示 ​编辑三.前端项目打包 ​编辑四.前端项目部署 1.上传项目…

YOLO目标检测——安全帽佩戴检测数据集【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;安全帽佩戴检测数据集可以用于实时检测工作人员是否按照要求佩戴了安全帽&#xff0c;以保障他们的安全数据集说明&#xff1a;安全帽佩戴检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富&#xff0c;图片分为带头盔和没带头…

智慧矿山:AI算法在带式运输机中的异物识别应用

随着现代农业和工业的发展&#xff0c;带式运输机在各种生产作业中发挥着越来越重要的作用。然而&#xff0c;在带式运输机运行过程中&#xff0c;可能会混入各种异物&#xff0c;这些异物的存在可能会对运输过程和设备本身造成损害。为了解决这一问题&#xff0c;本文将介绍一…

c++装饰器模式

前言 装饰器模式&#xff0c;就是可以对一个对象无限装饰一些东西&#xff0c;而且可以没有顺序。比如一个人可能只会说出他的名字&#xff0c;但是可以让他再说哈哈&#xff0c;可以说完哈哈之后再说哇哇。如何后面又不想装饰了&#xff0c;不需要改类原来的代码&#xff0c;…

基于深度学习的人脸性别年龄识别 - 图像识别 opencv 计算机竞赛

文章目录 0 前言1 课题描述2 实现效果3 算法实现原理3.1 数据集3.2 深度学习识别算法3.3 特征提取主干网络3.4 总体实现流程 4 具体实现4.1 预训练数据格式4.2 部分实现代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计…

智慧校园地下管线三维可视化管控平台减少人力和物力资源的浪费

随着科技的不断发展&#xff0c;三维可视化管理平台在各个领域得到了广泛的应用。三维可视化管理平台通过将数据以三维形式呈现&#xff0c;使得用户能够更直观地理解和分析数据&#xff0c;从而提高工作效率和决策质量。 VR数字孪生园区系统是通过将实际园区的各种数据和信息进…

RabbitMQ入门到实战教程,消息队列实战,改造配置MQ

RabbitMQ入门到实战教程&#xff0c;MQ消息中间件&#xff0c;消息队列实战-CSDN博客 3.7.Topic交换机 3.7.1.说明 Topic类型的Exchange与Direct相比&#xff0c;都是可以根据RoutingKey把消息路由到不同的队列。 只不过Topic类型Exchange可以让队列在绑定BindingKey 的时候…

如何优雅地单元测试 Kotlin/Java 中的 private 方法?

翻译自 https://medium.com/mindorks/how-to-unit-test-private-methods-in-java-and-kotlin-d3cae49dccd ❓如何单元测试 Kotlin/Java 中的 private 方法❓ 首先&#xff0c;开发者应该测试代码里的 private 私有方法吗&#xff1f; 直接信任这些私有方法&#xff0c;测试到…

系列四、全局配置mybatis-config.xml

一、全局配置文件中的属性 mybatis全局配置中的文件非常多&#xff0c;主要有如下几个&#xff1a; properties&#xff08;属性&#xff09;settings&#xff08;全局配置参数&#xff09;typeAliases&#xff08;类型别名&#xff09;typeHandlers&#xff08;类型处理器&am…

用前端框架Bootstrap和Django实现用户注册页面

01-新建一个名为“mall_backend”的Project 命令如下&#xff1a; CD E:\Python_project\P_001\myshop-test E: django-admin startproject mall_backend02-新建应用并注册应用 执行下面条命令依次创建需要的应用&#xff1a; CD E:\Python_project\P_001\myshop-test\mall…

模型应用系实习生-模型训练笔记(更新至线性回归、Ridge回归、Lasso回归、Elastic Net回归、决策树回归、梯度提升树回归和随机森林回归)

sklearn机械学习模型步骤以及模型 一、训练准备&#xff08;x_train, x_test, y_train, y_test&#xff09;1.1 导包1.2 数据要求1.21 导入数据1.22 数据类型查看检测以及转换1.22 划分数据 二、回归2.1 线性回归2.2 随机森林回归2.3 GradientBoostingRegressor梯度提升树回归2…

如何创建一个react项目

文章目录 前言前言打开小黑窗口npm init vite后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;react.js &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&am…

84.在排序数组中查找元素的第一个和最后一个位置(力扣)

目录 问题描述 代码解决以及思想 知识点 问题描述 代码解决以及思想 class Solution { public:vector<int> searchRange(vector<int>& nums, int target) {int left 0; // 定义左边界int right nums.size() - 1; // 定义右…

uniapp原生插件之安卓获取设备唯一标识

插件介绍 安卓获取设备唯一标识&#xff0c;集成了获取imei&#xff0c;获取安卓ID&#xff0c;获取GUID&#xff0c;获取获取OAID/AAID等 插件地址 安卓获取设备唯一标识 - DCloud 插件市场 超级福利 uniapp 插件购买超级福利 详细使用文档 uniapp 安卓获取设备唯一标…

安防视频监控平台EasyCVR服务器需要开启firewalld防火墙,该如何开放端口?

智能视频监控/视频云存储/集中存储/视频汇聚平台EasyCVR具备视频融合汇聚能力&#xff0c;作为安防视频监控综合管理平台&#xff0c;它支持多协议接入、多格式视频流分发&#xff0c;视频监控综合管理平台EasyCVR支持海量视频汇聚管理&#xff0c;可应用在多样化的场景上&…

MacOS安装git

文章目录 通过Xcode Command Lines Tool安装(推荐)终端直接运行git命令根据流程安装先安装Command Lines Tool后再安装git 官网下载二进制文件进行安装官方国外源下载二进制文件(不推荐)国内镜像下载二进制文件(推荐)安装git 通过Xcode Command Lines Tool安装(推荐) 简单来讲C…

Ubuntu 20.04设置虚拟内存 (交换内存swap)解决内存不足

数据库服务器程序在运行起来之后&#xff0c;系统内存不足。 在系统监控中发现&#xff0c;当数据库服务程序启动后&#xff0c;占用了大量内存空间&#xff0c;导致系统的剩余的内存往往只有几十MB。 在ubuntu系统中&#xff0c;swap空间就是虚拟内存&#xff0c;所以考虑在磁…