利用Python求解八数码难题
实验目的
- 实验内容
八数码问题也称为九宫问题。在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始状态转变成目标状态的移动棋子步数最少的移动步骤。 - 实验要求
分别利用宽度优先搜索和有序搜索算法求解八数码难题,给出搜索树,并给出从初始节点到目标节点的路径。
实验设备及软件环境
#####1. 电脑配置:
(1)处理器 : Intel i5-4210U CPU @ 1.70GHz, 2.40GHz
(2)安装内存: 8.00GB
(3)操作系统: Windows 10
(4)编程语言: Python
(5)软件环境: python 3.5 、numpy、matplotlib、scipy、Axure 7.0
(6)IDE : PyCharm 5.0.1
实验方法
算法描述
(1) 宽度优先搜索
如果搜索是以接近起始节点的程度依次扩展节点的,那么这种搜索就叫做宽度优先搜索。这种搜索是逐层进行的,在对下一层的任一节点进行搜索之前,必须搜索完本层的所有节点。
(2) 有序搜索
令f(n)f(n)f(n) 表示节点nnn的估价函数值,估算节点希望程度的量度。本次实验选择的f(n)f(n)f(n)的函数形式为:
f(n)=g(n)+h(n)f(n) = g(n) + h(n)f(n)=g(n)+h(n)
其中, g(n)g(n)g(n)为初始节点到当前节点的路径长度(深度), h(n)h(n)h(n)为当前节点“不在位”的将牌数。
有序搜索(ordered search),即最好优先搜索, 选择Open表上具有最小f值的节点作为下一个要扩展的节点。流程图
(1) 宽度优先搜索
(2) 有序搜索
- 程序代码 (python)
(1) 宽度优先搜索
__author__ = 'ysc'
import numpy as npclass State:def __init__(self, state, directionFlag=None, parent=None):self.state = state # state is a ndarray with a shape(3,3) to storage the stateself.direction = ['up', 'down', 'right', 'left']if directionFlag:self.direction.remove(directionFlag) # record the possible directions to generate the sub-statesself.parent = parentself.symbol = ' 'def getDirection(self):return self.directiondef showInfo(self):for i in range(3):for j in range(3):print(self.state[i, j], end=' ')print("\n")print('->')returndef getEmptyPos(self):postion = np.where(self.state == self.symbol)return postiondef generateSubStates(self):if not self.direction:return []subStates = []boarder = len(self.state) - 1 # the maximum of the x,yrow, col = self.getEmptyPos()if 'left' in self.direction and col > 0:#it can move to left s = self.state.copy()temp = s.copy()s[row, col] = s[row, col-1]s[row, col-1] = temp[row, col]news = State(s, directionFlag='right', parent=self)subStates.append(news)if 'up' in self.direction and row > 0: #it can move to upper places = self.state.copy()temp = s.copy()s[row, col] = s[row-1, col]s[row-1, col] = temp[row, col]news = State(s, directionFlag='down', parent=self)subStates.append(news)if 'down' in self.direction and row < boarder: #it can move to down places = self.state.copy()temp = s.copy()s[row, col] = s[row+1, col]s[row+1, col] = temp[row, col]news = State(s, directionFlag='up', parent=self)subStates.append(news)if self.direction.count('right') and col < boarder: #it can move to right places = self.state.copy()temp = s.copy()s[row, col] = s[row, col+1]s[row, col+1] = temp[row, col]news = State(s, directionFlag='left', parent=self)subStates.append(news)return subStatesdef solve(self):# generate a empty openTableopenTable = [] # generate a empty closeTablecloseTable = [] # append the origin state to the openTable openTable.append(self) steps = 1# start the loopwhile len(openTable) > 0: n = openTable.pop(0)closeTable.append(n)subStates = n.generateSubStates()path = []for s in subStates:if (s.state == s.answer).all():while s.parent and s.parent != originState:path.append(s.parent)s = s.parentpath.reverse()return path, steps+1openTable.extend(subStates)steps += 1else:return None, Noneif __name__ == '__main__':# the symbol representing the empty place# you can change the symbol at heresymbolOfEmpty = ' ' State.symbol = symbolOfEmpty # set the origin state of the puzzleoriginState = State(np.array([[2, 8, 3], [1, 6 , 4], [7, symbolOfEmpty, 5]])) # and set the right answer in terms of the originState.answer = np.array([[1, 2, 3], [8, State.symbol, 4], [7, 6, 5]]) s1 = State(state=originState.state)path, steps = s1.solve()if path: # if find the solutionfor node in path: # print the path from the origin to final state node.showInfo()print(State.answer)print("Total steps is %d" % steps)
(2)有序搜索算法
__author__ = 'ysc'
import numpy as npclass State:def __init__(self, state, directionFlag=None, parent=None, depth=1):self.state = state # state is a ndarray with a shape(3,3) to storage the stateself.direction = ['up', 'down', 'right', 'left']if directionFlag:self.direction.remove(directionFlag) # record the possible directions to generate the sub-statesself.parent = parentself.symbol = ' 'self.answer = np.array([[1, 2, 3], [8, State.symbol, 4], [7, 6, 5]])self.depth = depth# calculate the num of elements which are not in the proper positionnum = 0for i in range(len(state)):for j in range(len(state)):if self.state[i, j] != ' 'and self.state[i, j] != self.answer[i, j]:num += 1self.cost = num + self.depthdef getDirection(self):return self.directiondef showInfo(self):for i in range(3):for j in range(3):print(self.state[i, j], end=' ')print("\n")print('->')returndef getEmptyPos(self):postion = np.where(self.state == self.symbol)return postiondef generateSubStates(self):if not self.direction:return []subStates = []# the maximum of the x,yrow, col = self.getEmptyPos()if 'left' in self.direction and col > 0: #it can move to left places = self.state.copy()temp = s.copy()s[row, col] = s[row, col-1]s[row, col-1] = temp[row, col]news = State(s, directionFlag='right', parent=self, depth=self.depth+1)subStates.append(news)if 'up' in self.direction and row > 0: #it can move to upper places = self.state.copy()temp = s.copy()s[row, col] = s[row-1, col]s[row-1, col] = temp[row, col]news = State(s, directionFlag='down', parent=self, depth=self.depth+1)subStates.append(news)if 'down' in self.direction and row < boarder:#it can move to down place s = self.state.copy()temp = s.copy()s[row, col] = s[row+1, col]s[row+1, col] = temp[row, col]news = State(s, directionFlag='up', parent=self, depth=self.depth+1)subStates.append(news)if self.direction.count('right') and col < boarder:#it can move to right place s = self.state.copy()temp = s.copy()s[row, col] = s[row, col+1]s[row, col+1] = temp[row, col]news = State(s, directionFlag='left', parent=self, depth=self.depth+1)subStates.append(news)return subStatesdef solve(self):# generate a empty openTableopenTable = []# generate a empty closeTable closeTable = []# append the origin state to the openTable openTable.append(self)# denote the steps it travels steps = 0 while len(openTable) > 0: # start the loopn = openTable.pop(0)closeTable.append(n)subStates = n.generateSubStates()path = []for s in subStates:if (s.state == s.answer).all():while s.parent and s.parent != originState:path.append(s.parent)s = s.parentpath.reverse()return path, steps+1openTable.extend(subStates)# sort the openTable in terms of the costopenTable.sort(key=lambda x: x.cost) steps += 1else:return None, None
if __name__ == '__main__':# the symbol representing the empty placesymbolOfEmpty = ' '# you can change the symbol at here State.symbol = symbolOfEmpty# set the origin state of the puzzle originState = State(np.array([[2, 8, 3], [1, 6 , 4], [7, symbolOfEmpty, 5]])) State.answer = np.array([[1, 2, 3], [8, State.symbol, 4], [7, 6, 5]]) s1 = State(state=originState.state)path, steps = s1.solve()if path: # if find the solutionfor node in path:# print the path from the origin to final state node.showInfo()print(State.answer)print("Total steps is %d" % steps)
实验结果
绘图软件为:Axure 7.0
- 搜索树
(1)DFS
(2) 有序搜索
- 搜索路径
实验分析
- 结果分析
(1) 宽度优先搜索
由实验结果可知,宽度优先搜索扩展节点个数为4,生成节点个数为26。
(扩展节点:路径中的节点数-1;生成节点:搜索树中节点数目-1)
(2) 有序搜索
由实验结果可知,有序搜索扩展节点个数为4,生成节点个数为12。
(扩展节点:路径中的节点数-1;生成节点:搜索树中节点数目-1)
2. 方法特点
(1) 宽度优先搜索 - 宽度优先搜索又称广度优先搜索,“广度”一词形象地揭示了这种搜索是逐层进行的:在对下一层的任一节点进行搜索之前,必须搜索完本层的所有节点。
- 不需要重排Open表
- 一般只适用于求解比较简单的问题。
- 若问题有解,宽度优先搜索一定可以求得,并且求出的是最优解。
(2) 有序搜索
有序搜索利用到启发式信息,对Open表中元素进行了重排,选择最有希望的节点加以扩展,搜索效率较盲目搜索大为提高。
3. 区别
宽度优先搜索属于盲目搜索,没有利用到启发信息,故效率较低;而有序搜索利用到节点本身的特性,将其作为启发式信息,对Open表进行重排,每一次选择都是最优的,具有贪心性质,搜索效率大为提高。
结论
综上所述,可以明显看出宽度优先搜索与有序搜索的效率差异。这启示我们在解决生活问题时,不仅仅是需要找到一个通用的(general)算法框架,因为虽然可以求出解,但是效率很低,我们更需要根据实际问题具体分析,通过问题本身,提炼出更有效的启发式信息,这样才能提高解的效率。
利用Python求解八数码难题相关推荐
- 基于Python实现的AStar求解八数码问题
资源下载地址:https://download.csdn.net/download/sheziqiong/86776612 资源下载地址:https://download.csdn.net/downl ...
- 习题:八数码难题(双向BFS)
八数码难题(wikioi1225) [题目描述] 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出 ...
- 【codevs1225】八数码难题,如何精确地搜索
1225 八数码难题 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description Yours和zero在研究A*启发式算法.拿到一道 ...
- 洛谷P1379八数码难题
题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中. 要求解的问题是:给出一种初始布局(初始状态)和目标布局(为 ...
- 八数码难题的多种解法
蔡自兴老师的<人工智能及其应用>这本书的第3章里面讲解了很多种搜索方法,因为看的不是很懂,所以网上就找了资源来帮助理解. 为了帮助各位更好的理解,在此,仅以八数码难题为实例来解释说明. # ...
- 8puzzle java 代码_八数码难题(8 puzzle)深度优先和深度优先算法
1搜索策略 搜索策略是指在搜索过程中如何选择扩展节点的次序问题.一般来说,搜索策略就是采用试探的方法.它有两种类型:一类是回溯搜索,另一类是图搜索策略. 2盲目的图搜索策略 图搜索策略又可分为两种:一 ...
- python 物理学中的应用_利用python求解物理学中的双弹簧质能系统详解
前言 本文主要给大家介绍了关于利用python求解物理学中双弹簧质能系统的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 物理的模型如下: 在这个系统里有两个物体,它们的质 ...
- python代码物理_利用python求解物理学中的双弹簧质能系统详解
前言 本文主要给大家介绍了关于利用python求解物理学中双弹簧质能系统的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 物理的模型如下: 在这个系统里有两个物体,它们的质 ...
- 利用python求解节点介数和边介数
利用python求解节点介数和边介数 利用networkx里面的函数betweenness_centrality(G)来求解节点介数和函数edge_betweenness_centrality(G)来 ...
最新文章
- python数字类型转换函数_Python的数据类型转换函数
- oracle tranc,oracle函数trunc的使用
- Linux下简单线程池的实现
- SAP Spartacus 3.3.0 版本服务器端渲染的优化
- 计算机里创建本地磁盘分区,大神教你如何将本地硬盘进行分区!
- 开源私有云盘python_用Seafile不花钱搭建高安全性局域网私有云盘
- mysql数据库存储过程异常处理
- 最新可使用在线音乐网站+多解析源码
- Git利用命令行提交代码步骤
- 电脑键盘部分按键失灵_笔记本键盘部分失灵怎么办,笔记本个别键失灵的处理方法...
- 经营三类医疗器械不使用计算机,第三十条经营第三类医疗器械的企业,应当具有符合医疗器械经营质量管理要求的计算机信息管理系统,保证经营的产品可追溯。计算机信息管理系统应当具有以下功能:...
- POJ3278抓牛Catch That Cow
- S4 BOM批量修改
- STM32硬件SPI通过fm17550读取身份证UID,识别银行卡,识别TYPEA与TYPEB
- 企业级DevOps容器云平台流水线综合解决方案详解(一)
- 一个可以免费下载O Reilly的书籍的地方
- 爬山算法改进粒子群求解测试测试函数shubert,测试函数的100种优化方法之14
- Spring Cloud Gateway 之Predict篇
- x64dbg调试程序遇到异常:406D1388,MS_VC_EXCEPTION. E06D7363, CPP_EH_EXCEPTION
- Qt6-网络关机助手(开机自启版)新增定时关机功能
热门文章
- FM/AM收音机原理
- shell基础(2):编程基础之变量:全局/局部/环境变量(作用域、定义、操作)、位置参数、数组
- calsite原理_Calcite 处理一条SQL - II (Rels Into Planner)
- 微服务之RPC(远程过程调用)的四种方式
- 软考是什么考试?软件水平考试介绍
- ZJUT online OJ c++通关模拟题(problem1335-problem1516) 题解
- 《机器学习实战》笔记——第三章:决策树实战
- vue项目首屏加载优化
- IntelliJ IDEA删除项目
- 用python画简单雪花剪纸步骤图解_Python+Selenium+Beautiful Soap抓取贝贝拼团爆款