【人工智能实验】A*算法求解8数码问题 golang
人工智能经典问题八数码求解
实际上是将求解转为寻找最优节点的问题,算法流程如下:
- 求非0元素的逆序数的和,判断是否有解
- 将开始状态放到节点集,并设置访问标识位为true
- 从节点集中取出h(x)+g(x)最小的节点
- 判断取出的节点的状态是不是最终状态,如果是的话则回溯打印
- 找出取出的节点的状态中的0的位置
- 对取出的节点进行move操作,包含up down left right
- 如果move后的状态的访问标识位为false,则添加。否则什么都不做
需要注意:节点的数据结构如下
- 状态:int数组
- h(x):当前节点的状态到目标状态的距离
- g(x):当前节点的状态到初始状态的距离
- 动作:到当前节点所进行的move类型
- 父节点:记录上一个状态,方便回溯打印
使用go语言实现如下
-
main.go
package mainimport ("container/heap""github.com/gookit/color""log""os""os/signal""syscall" )var (start = []int{2, 8, 3, 1, 6, 4, 7, 0, 5}target = []int{1, 2, 3, 8, 0, 4, 7, 6, 5} ) var (movables = []string{"up", "down", "left", "right"}moveOffsets = map[string]int{"up": -3, "down": 3, "left": -1, "right": 1} ) var (visited = make(map[string]bool) )func main() {color.BgCyan.Println("Y02114562")printFun := func(list []int) {for _, i := range list {color.BgLightCyan.Print(i, ",")}color.BgLightCyan.Print("\n")}printFun(start)printFun(target)if reverseSum(start) != reverseSum(target) {log.Fatal("不可解")}path, steps := solve(start)if steps == -1 {log.Fatal("No solution")}color.BgGreen.Println("只需:", steps, "步")color.BgGreen.Println("操作:", path)quit := make(chan os.Signal, 1)signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)<-quit }// 启发函数:h(x) 从当前状态到目标的距离 func manhattanDistance(state []int) int {distance := 0for i := 0; i < 9; i++ {if state[i] != 0 {row1, col1 := i/3, i%3// 遍历所有不为0的点,计算他与他的目标位置的曼哈顿距离for j := 0; j < 9; j++ {if state[i] == target[j] {row2, col2 := j/3, j%3distance += abs(row1-row2) + abs(col1-col2)break}}}}return distance }// 启发式搜索:八数码问题求解 func solve(start []int) ([]string, int) {// 创建起始节点startNode := &Node{State: start,Heuristic: manhattanDistance(start),G: 0,PrevMove: "",PrevNode: nil,}// 创建优先队列pq := make(PriorityQueue, 0)heap.Init(&pq)heap.Push(&pq, startNode)visited[listToString(startNode.State)] = true// A*搜索for pq.Len() > 0 {currentNode := heap.Pop(&pq).(*Node)// 到达目标状态,返回路径if listToString(currentNode.State) == listToString(target) {path := make([]string, 0)for currentNode.PrevNode != nil {path = append(path, currentNode.PrevMove)currentNode = currentNode.PrevNode}return func(slice []string) ([]string, int) {for i, j := 0, len(slice)-1; i < j; i, j = i+1, j-1 {slice[i], slice[j] = slice[j], slice[i]}return slice, len(path)}(path)}zeroIndex := func(state []int) int {for i, num := range state {if num == 0 {return i}}return -1}(currentNode.State)for _, move := range movables {if canMove(move, zeroIndex) {newState := make([]int, len(currentNode.State))copy(newState, currentNode.State)newZeroIndex := zeroIndex + moveOffsets[move]newState[zeroIndex], newState[newZeroIndex] = newState[newZeroIndex], newState[zeroIndex]// 创建新节点newNode := &Node{State: newState,Heuristic: manhattanDistance(newState),G: currentNode.G + 1,PrevMove: move,PrevNode: currentNode,}// 如果新状态未被访问,则加入优先队列和已访问集合if !visited[listToString(newState)] {heap.Push(&pq, newNode)visited[listToString(newState)] = true}}}}// 没有找到解return nil, -1 } -
node.go
package main// Node 节点结构体 type Node struct {State []int // 当前状态Heuristic int // 启发函数值G int // 初始节点到当前节点PrevMove string // 上一步移动的方向PrevNode *Node // 上一步的节点 }// PriorityQueue 优先队列 type PriorityQueue []*Node// Len 优先队列的方法:计算长度 func (pq PriorityQueue) Len() int {return len(pq) }// Less 优先队列的方法:比较优先级 func (pq PriorityQueue) Less(i, j int) bool {return pq[i].Heuristic+pq[i].G < pq[j].Heuristic+pq[j].G }// Swap 优先队列的方法:交换元素 func (pq PriorityQueue) Swap(i, j int) {pq[i], pq[j] = pq[j], pq[i] }// Push 优先队列的方法:向队列中插入元素 func (pq *PriorityQueue) Push(x interface{}) {node := x.(*Node)*pq = append(*pq, node) }// Pop 优先队列的方法:从队列中弹出元素 func (pq *PriorityQueue) Pop() interface{} {old := *pqn := len(old)node := old[n-1]*pq = old[0 : n-1]return node } -
tool.go
package mainimport "fmt"// 辅助函数:判断是否可移动 func canMove(move string, zeroIndex int) bool {if move == "up" && zeroIndex >= 3 {return true}if move == "down" && zeroIndex <= 5 {return true}if move == "left" && zeroIndex%3 != 0 {return true}if move == "right" && zeroIndex%3 != 2 {return true}return false }// 辅助函数:将[]int转换为字符串 func listToString(state []int) string {str := ""for _, num := range state {str += fmt.Sprintf("%d", num)}return str }// 辅助函数:求除了0之外的逆序和 func reverseSum(arr []int) bool {sum := 0for i := 1; i < len(arr); i++ {if arr[i] != 0 {for j := 0; j < i; j++ {if arr[j] > arr[i] {sum++}}}}return sum%2 != 0 }// 辅助函数:计算绝对值 func abs(num int) int {if num < 0 {return -num}return num }
运行效果

相关文章:
【人工智能实验】A*算法求解8数码问题 golang
人工智能经典问题八数码求解 实际上是将求解转为寻找最优节点的问题,算法流程如下: 求非0元素的逆序数的和,判断是否有解将开始状态放到节点集,并设置访问标识位为true从节点集中取出h(x)g(x)最小的节点判断取出的节点的状态是不…...
Kafka学习笔记(二)
目录 第3章 Kafka架构深入3.3 Kafka消费者3.3.1 消费方式3.3.2 分区分配策略3.3.3 offset的维护 3.4 Kafka高效读写数据3.5 Zookeeper在Kafka中的作用3.6 Kafka事务3.6.1 Producer事务3.6.2 Consumer事务(精准一次性消费) 第4章 Kafka API4.1 Producer A…...
Typora for Mac:打造全新文本编辑体验
Typora for Mac是一款与众不同的文本编辑器,它不仅拥有直观易用的界面,还融合了Markdown语法和富文本编辑的功能,为用户带来了前所未有的写作和编辑体验。 一、简洁明了的界面设计 Typora for Mac的界面简洁明了,让用户可以专注…...
TikTok与媒体素养:如何辨别虚假信息?
在当今数字时代,社交媒体平台如TikTok已经成为信息传播和社交互动的主要渠道之一。然而,随之而来的是虚假信息的泛滥,这对用户的媒体素养提出了严峻的挑战。本文将探讨TikTok平台上虚假信息的现象,以及如何提高媒体素养࿰…...
Spring Boot 中使用 ResourceLoader 加载资源的完整示例
ResourceLoader 是 Spring 框架中用于加载资源的接口。它定义了一系列用于获取资源的方法,可以处理各种资源,包括类路径资源、文件系统资源、URL 资源等。 以下是 ResourceLoader 接口的主要方法: Resource getResource(String location)&am…...
1688往微信小程序自营商城铺货商品采集API接口
一、背景介绍 随着移动互联网的快速发展,微信小程序作为一种新型的电商形态,正逐渐成为广大商家拓展销售渠道、提升品牌影响力的重要平台。然而,对于许多传统企业而言,如何将商品信息快速、准确地铺货到微信小程序自营商城是一个…...
QStatusBar开发详解
一、QStatusBar接口说明 QStatusBar 类是 Qt 中用于创建和管理状态栏的类。它继承自 QFrame 类,提供了在主窗口底部显示消息、进度等信息的功能。以下是一些 QStatusBar 类的重要接口: 1.1 QStatusBar构造函数 QStatusBar(QWidget *parent nullptr);…...
后端接口性能优化分析-程序结构优化
👏作者简介:大家好,我是爱吃芝士的土豆倪,24届校招生Java选手,很高兴认识大家📕系列专栏:Spring源码、JUC源码🔥如果感觉博主的文章还不错的话,请👍三连支持&…...
【SpringBoot3+Vue3】三【实战篇】-后端(优化)
目录 一、登录优化-redis 1、SpringBoot集成redis 1.1 pom 1.2 yml 1.3 测试程序(非必须) 1.4 启动redis,执行测试程序 2、令牌主动失效(代码优化) 2.1 UserController设置token到redis 2.2 登录拦截器Log…...
DevExpress中文教程 - 如何在macOS和Linux (CTP)上创建、修改报表(上)
DevExpress Reporting是.NET Framework下功能完善的报表平台,它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集,包括数据透视表、图表,因此您可以构建无与伦比、信息清晰的报表。 DevExpress Reports — 跨平台报表组件&#x…...
一个iOS tableView 滚动标题联动效果的实现
效果图 情景 tableview 是从屏幕顶部开始的,现在有导航栏,和栏目标题视图将tableView的顶部覆盖了 分析 我们为了达到滚动到某个分区选中标题的效果,就得知道 展示最顶部的cell或者区头在哪个分区范围内 所以我们必须首先获取顶部的位置 …...
代码执行相关函数以及简单例题
代码/命令 执行系列 相关函数 (代码注入)...
大数据爬虫分析基于Python+Django旅游大数据分析系统
欢迎大家点赞、收藏、关注、评论啦 ,由于篇幅有限,只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 基于Python和Django的旅游大数据分析系统是一种使用Python编程语言和Django框架开发的系统,用于处理和分…...
C# 结构体介绍
文章目录 定义结构体实例化结构体结构体的值类型特性结构体和类的区别限制 C# 中的结构体(Struct)是一种值类型数据结构,用于封装不同或相同类型的数据成一个单一的实体。结构体非常适合用来表示轻量级的对象,比如坐标点、颜色值或…...
【机器学习】特征工程:特征预处理,归一化、标准化、处理缺失值
特征预处理采用的是特定的统计方法(数学方法)将数据转化为算法要求的数字 1. 数值型数据 归一化,将原始数据变换到[0,1]之间 标准化,数据转化到均值为0,方差为1的范围内 缺失值,缺失值处理成均值、中…...
Pytorch torch.norm函数详解用法
torch.norm参数定义 torch版本1.6 def norm(input, p"fro", dimNone, keepdimFalse, outNone, dtypeNone)input input (Tensor): the input tensor 输入为tensorp p (int, float, inf, -inf, fro, nuc, optional): the order of norm. Default: froThe following …...
【DevOps】Git 图文详解(二):Git 安装及配置
Git 图文详解(二):Git 安装及配置 1.Git 的配置文件2.配置 - 初始化用户3.配置 - 忽略.gitignore Git 官网:https://www.git-scm.com/ 下载安装包进行安装。Git 的使用有两种方式: 命令行:Git 的命令通过系…...
亚马逊美国站CPC认证ASTM F963测试项目要求有哪些?
ASTM F963是美国材料和试验联合会(ASTM)制定的儿童玩具安全性的标准规范,专门针对儿童玩具产品的安全性进行了规定和要求。 ASTM F963标准的内容和要求包括: 1、物理机械性能:规定了玩具的物理机械性能要求࿰…...
通付盾Web3专题 | KYT/AML:Web3合规展业的必要条件
与传统证券一样,基于区块链技术发展出来的虚拟资产交易所经历了快速发展而缺乏有效监管的行业早期。除了科技光环加持的各种区块链项目方、造富神话之外,交易所遭到黑客攻击、内部偷窃作恶、甚至经营主体异常而致使投资人血本无归的案例亦令人触目惊心。…...
Centos8配置Zabbix5.0中文汉化
1.点击【Sign in】按钮,输入用户名和密码进入Zabbix的首页,结果如图。 2.点击左边导航栏的【User settings】链接,进入用户个性化设置界面,结果如图。 3.在搭建Zabbix的虚拟机上使用yum命令下载中文包。 yum install glibc-langpa…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
GitFlow 工作模式(详解)
今天再学项目的过程中遇到使用gitflow模式管理代码,因此进行学习并且发布关于gitflow的一些思考 Git与GitFlow模式 我们在写代码的时候通常会进行网上保存,无论是github还是gittee,都是一种基于git去保存代码的形式,这样保存代码…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
