人工智能实验——八数码难题

这篇具有很好参考价值的文章主要介绍了人工智能实验——八数码难题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

人工智能实验——八数码难题


八数码难题简介


八数码问题指的是定义一个3$\times$3的格子,然后把1-8八个数字随机放入这些格子中,然后排列成规则的格子。就像下面图所示:

人工智能实验——八数码难题

而本文所要解决的是,如何设计一个程序解决八数码问题。解决八数码问题其实算是一个搜索问题。

八数码难题所用到的算法简介


  • BFS广度优先搜索算法

    以接近起始节点的程度依次扩展节点的搜索方法 宽度优先搜索是逐层进行的;在对下一层的任一节点进行搜 索之前,必须搜索完本层的所有节点。

    人工智能实验——八数码难题

  • DFS深度优先搜索算法

    优先扩展最新产生的(即最深的)节点的搜索方法 深度优先搜索沿着状态空间某条单一的路径从起始节点向下 进行下去;只有当搜索到达一个没有后裔的状态时,它才考 虑另一条替代的路径。 状态空间搜索树的深度可能为无限深,往往给出一个节点扩 展的最大深度—深度界限

    人工智能实验——八数码难题

  • 贪婪算法(本文未利用)

    贪婪算法的话,它是一种特殊的DFS算法,若设计得不好得话就会直接退化为DFS算法。在这里得话可以利用每个元素到目标点的曼哈顿距离来作为贪婪算法的引导元素。也可以利用在正确位置的元素的个数作为引导。

  • 代价优先算法(本文未利用)

    代价算法的话,一般以当前深度作为代价。优先搜索深度小的。

  • A*算法

    A*算法结合了贪婪算法与代价优先算法,利用两者的和作为代价利用广度优先的数据结构为基础来进行搜索。

人工智能实验——八数码难题

代码实现解释


1.定义八数码类

首先定义了一个八数码类,此类生成的对象是用来存储八数码数据的。八数码类的对象相当于状态空间。此类中包含了四类数据,分别为八数码的排列顺序、父节点、深度、A*算法对应的代价。下面为八数码类。

# 八数码矩阵
class Ef:
    def __init__(self, value, parent=0, depth=1, hscore=0):
        self.value = value
        self.parent = parent  # 定义父节点 若不输入父节点 则自定义其为根 也就是说当parent为0时为根
        self.depth = depth #深度 默认为1
        self.fscore = depth + hscore #A*算法的代价

2.定义操作类

在完成八数码类的编写后,接着的是后继函数即操作。对于后继函数,我的做法是再次定义一个Op类。此类中的函数只有两个,分别为初始化类与空白移动类。在初始化类中,我对传入的八数码对象进行了复制赋值(之所以怎么做是因为Python中的对象类似于指针而不是真正实体)。然后设置了遍历寻找八数码对象中0的位置索引。最后设置了方向参数字典,这样做可以缩减代码量。

在对函数初始化完后,开始编写移动函数,这个函数才是操作类中的主体,这个类的功能主要就是将0与某个方向的数进行替换。一开始编写这个函数时其实分成了四个函数来写的,即上下左右。但是后面发现这些函数的重复性大,于是将不同方向的特定参数整理成了字。将四段代码整理成了一段只要传入字典中的某个值即可移动0。最后返回的是移动成功后的嵌套列表。补充:函数内部拥有一定的边界判别语句,若超界了会返回0。下图为操作类的功能图。

人工智能实验——八数码难题

# 包含所有操作的类 注意python赋值后的对象还是同一个对象 所以要用copy
class Op:
    def __init__(self, ef):
        self.ef_value = copy.deepcopy(ef.value)
        for i in range(0, 3):  # 获取空位置的索引
            for j in range(0, 3):
                if self.ef_value[i][j] == 0:
                    self.j, self.i = j, i
                    break
        self.direction = {'left': [self.j == 0, 0, -1], 'right': [self.j == 2, 0, 1], \
                          'up': [self.i == 0, -1, 0], 'down': [self.i == 2, 1, 0]}  # 方向配置字典

    def move(self, direc='left'):  # 交换操作
        op = self.direction[direc]
        if op[0]:  # 如果在第一列则无法交换 返回0
            return 0
        else:  # 否则交换
            temp = self.ef_value[self.i + op[1]][self.j + op[2]]
            self.ef_value[self.i + op[1]][self.j + op[2]] = self.ef_value[self.i][self.j]
            self.ef_value[self.i][self.j] = temp
            return self.ef_value

3.编写Solution类

完成以上的类的编写后,开始编写程序的主体代码。对于主体,我也还是写了一个Solution类。这个类中的数据主要包含Open表、Closed表、开始状态、目标状态。下图为Solution类各项数据的图解。

人工智能实验——八数码难题

class Solution:
    def __init__(self, ef):
        self.openT = []  # 定义open表  注意需要用到python自带的队列库
        self.openT.append(ef)  # 一开始将其添加进open表
        self.closeT = []  # 定义close表
        self.start_state = ef  # 定义开始状态
        self.des_state = [[1, 2, 3], [8, 0, 4], [7, 6, 5]]  # 定义最终状态
        self.des_state_dict = {1:[0,0],2:[0,1],3:[0,2],8:[1,0]
                               ,0:[1,1],4:[1,2],7:[2,0],6:[2,1],5:[2,2]} #字典格式

初始化完Solution类后,我定义了多个基础的函数,这些函数基本上都是判断函数。包括状态是否到达目标状态判断函数、状态是否重复判断函数、是否可解函数。对于前两个,函数本体基本上都是用推导式一句完成的。而对于是否可解函数相对复杂。此判断首先是把八数码矩阵变成一维的形式,然后从第一个位置开始(除0外)记录每个元素前面比此元素大的个数,并把这些个数相加。如果最后得到的是偶数则有解否则无解。下图为判断函数的代码截图。*参考:*http://t.csdn.cn/0vyzV

    def iSolve(self,ef): #八数码是否有解判断 有解则返回1
        #转一维列表
        onedi = [ef.value[0][i] for i in range(3)] + [ef.value[1][2]] + \
                [ef.value[2][i] for i in range(2, -1, -1)] + [ef.value[1][i] for i in range(2)]
        oxe = 0 #计算逆序
        for i in range(1, 9):
            if onedi[i] != 0:
                for j in range(i):
                    oxe += 1 if onedi[j] > onedi[i] else 0
        return 1 if oxe % 2 == 0 else 0

4.extend函数.

除了以上的基础函数外,还有一个十分重要的基础函数。此函数是用来拓展的。此函数内部包含过滤机制,如果拓展生成的嵌套列表在closed表的话就丢弃,如果不在的话就计算深度并把父节点、深度、代价、嵌套列表传入一个新的八数码对象中,然后添加到open表中。

    def extend(self, ef):  # 拓展节点
        ex_direct = ['up', 'down', 'left', 'right']
        for d in ex_direct:
            temp = Op(ef).move(d)  # 由于这里用到了 copy深度复制  所以就要用一下方法阻止循环
            if temp:  # 如果可以上移则执行并且上行的结果不在closeT
                for i in self.closeT:  # 这里还可以重构
                    if i == temp:
                        break
                else:
                    ef_d = Ef(temp, ef, ef.depth+1, self.h(temp))  # 定义一个新对象 值为返回的上行结果 父节点为ef
                    #若要改h(n)在上面改
                    self.openT.append(ef_d)

人工智能实验——八数码难题

5.BFS算法

在一切都铺垫好后开始编写搜索算法,首先写的是BFS算法函数。进入函数后首先开始记录当前时间并把它命定义为start_time。然后判断传入的八数码对象是否有解,若无解则放回“No Solution!”,否则进入下面操作。判断Open表是否为空,若为空则放回”Failure”否则进入下面操作。检测Open表队首是否为目标状态,若不为目标状态则对队首元素进行拓展,并把队首纳入closed表中然后弹出。若已经是目标则遍历目标的父节点直到无父节点。然后打印这些父节点与程序运行时间与节点深度。以下为流程图

人工智能实验——八数码难题

    def BFS(self):  # 广度搜索
        start_time = time.time()
        if self.iSolve(self.openT[0]):
            while self.openT:  # 判断openT是否空表
                if self.isDes(self.openT[0]):
                    result = []
                    pointer = self.openT[0]
                    result.append(pointer.value)
                    while pointer.parent:
                        pointer = pointer.parent
                        result.append(pointer.value)
                    print(f'当前深度:{self.openT[0].depth}\n程序运行时间:{time.time() - start_time}s'
                          f'\n以下为推导过程(BFS)')
                    while result:
                        print(result.pop())  # 逆序打印
                    return "Success"
                else:
                    self.closeT.append(self.openT[0].value)  # 给closeT添加值
                    self.extend(self.openT[0])  # 若不是结果的话则拓展ef
                    self.openT.pop(0)  # 出队
            else:
                return "Failure"
        else:
            return 'No Solution!'

6.DFS算法

对于DFS其代码与BFS的类似,不同的地方在于其利用的数据结构是栈而不是队列,所以它首先检测的是最后一个元素是否是目标,并且也是首先对最后一个元素进行拓展。除此之外,DFS还对此进行了深度的限制。下图为我制作的程序在DFS上的流程图。

人工智能实验——八数码难题

    def DFS(self,depth=20): #深度搜索 需要传入深度参数 默认为100
        start_time = time.time()
        if self.iSolve(self.openT[0]):
            while self.openT:  # 判断openT是否空表且是否超过深度
                if self.isDes(self.openT[-1]): #检测倒数第一个
                    result = []
                    pointer = self.openT[-1]
                    result.append(pointer.value)
                    while pointer.parent:
                        pointer = pointer.parent
                        result.append(pointer.value)
                    print(f'当前深度:{self.openT[-1].depth}\n程序运行时间:{time.time() - start_time}s'
                          f'\n以下为推导过程(DFS)')
                    while result:
                        print(result.pop())  # 逆序打印
                    return "Success"
                else:
                    self.closeT.append(self.openT[-1].value)  # 给closeT添加值
                    if self.openT[-1].depth < depth: #深度限制
                        self.extend(self.openT.pop())  # 若不是结果的话则拓展ef
                    else:
                        self.openT.pop()
            else:
                return "Failure"
        else:
            return 'No Solution!'

7.A*算法

而A*算法大体上的程序结构和DFS与BFS是一致的,但是其利用的是优先队列。每一次拓展后都会根据代价的值对OPEN表进行排序,取代价最小的到队首然后对队首进行判断是否为目标,若为目标则打印结果否则进行拓展并排序。而这里的代价有g(n)与h(n)组成,g(n)是当前状态的深度利用的是DFS中的深度接口,而h(n)则是自己设计的。我设计了两种h(n),第一种是八数码九宫格里面各个元素与目标元素的差异个数。另外一种是各个元素到目标元素的最短距离的距离之和。附件中提供的程序利用的是第一种,第二种在代码中也有但是需要更改下接口。下图为A*算法的流程图。

人工智能实验——八数码难题

    def astar(self):
        start_time = time.time()
        if self.iSolve(self.openT[0]):
            while self.openT:  # 判断openT是否空表且是否超过深度
                if self.isDes(self.openT[0]): #检测倒数第一个
                    result = []
                    pointer = self.openT[0]
                    result.append(pointer.value)
                    while pointer.parent:
                        pointer = pointer.parent
                        result.append(pointer.value)
                    print(f'当前深度:{self.openT[0].depth}\n程序运行时间:{time.time() - start_time}s'
                          f'\n以下为推导过程(A*)')
                    while result:
                        print(result.pop())  # 逆序打印
                    return "Success"
                else:
                    self.closeT.append(self.openT[0].value)  # 给closeT添加值
                    self.extend(self.openT[0])  # 若不是结果的话则拓展ef
                    self.openT.pop(0)  # 出队
                    self.openT.sort(key=lambda x:x.fscore) #排序 根据fscore排序
            else:
                return "Failure"
        else:
            return 'No Solution!'

运行结果显示


以上为程序设计的描述部分。对程序设计完后我对程序进行了一些测试,包括不可解八数码的测试,三种算法的测试。以下为测试结果。图9是不可解八数码的测试,结果返回正确。

人工智能实验——八数码难题

下图分别对应的是A*、BFS、DFS三种算法,三者均是对同一个八数码的测试。由此可以看出三者的运行时间有一定的区别。

人工智能实验——八数码难题

代码附件


源代码下载

https://download.csdn.net/download/weixin_51735061/85375158

程序可视化


人工智能实验——八数码难题

上面的为演示,做法在https://blog.csdn.net/weixin_51735061/article/details/125656323文章来源地址https://www.toymoban.com/news/detail-412406.html

到了这里,关于人工智能实验——八数码难题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 人工智能导论——A*算法实验

    一、实验目的: 熟悉和掌握启发式搜索的定义、估价函数和算法过程,并利用A*算法求解N数码难题,理解求解流程和搜索顺序。 二、实验原理: A*算法是一种启发式图搜索算法,其特点在于对估价函数的定义上。对于一般的启发式图搜索,总是选择估价函数 f 值最小的节点

    2024年02月06日
    浏览(53)
  • 【人工智能Ⅰ】实验2:遗传算法

    实验2  遗传算法实验 一、实验目的 熟悉和掌握遗传算法的原理、流程和编码策略,理解求解TSP问题的流程并测试主要参数对结果的影响,掌握遗传算法的基本实现方法。 二、实验原理 旅行商问题,即TSP问题(Traveling Salesman Problem)是数学领域中著名问题之一。假设有一个旅

    2024年02月04日
    浏览(49)
  • 【人工智能】实验一:产生式系统实验与基础知识

    实验目的 熟悉一阶谓词逻辑和产生式表示法; 掌握产生式系统的运行机制,以及基于规则推理的基本方法。 实验内容 设计并编程实现一个飞行生物的小型产生式系统。 实验要求 具体应用领域自选,具体系统名称自定。 用一阶谓词逻辑和产生式规则作为知识表示,利用产生

    2024年02月02日
    浏览(203)
  • 人工智能头歌实验(盲目搜索)

    本关任务:编写代码实现广度优先搜索一个给定的树。 相关知识 为了完成本关任务,你需要掌握广度优先搜索算法的原理与实现。 广度优先搜索步骤 广度优先搜索一般是采用先进先出( FIFO )的队列来实现的,在这里我们用到了两个表: Open :是一个 先进先出的队列 ,存

    2024年01月18日
    浏览(42)
  • 人工智能安全实验一 入侵检测

    实验         一             项目名称:          入侵检测          一、实验目的    对数据集进行数据处理,使用信息增益方法来选取特征,产生训练集和测试集,并对数据进行归一化,构建模型,并对模型进行训练,得到函数的系数。构建分类器,最大化

    2024年01月22日
    浏览(48)
  • 【人工智能Ⅱ】实验2:VGG图像分类

    实验2:VGG图像分类 一:实验目的与要求 1:掌握VGG网络的原理与结构。 2:学会利用VGG网络建立训练模型,并对模型进行评估。 3:学会使用VGG网络进行分类。 二:实验内容 1:用VGG网络对自选图像数据集进行多分类预测。 2:应用图像增强方法进行数据集的扩充。 3:调整

    2024年04月26日
    浏览(44)
  • 【人工智能Ⅰ】实验7:K-means聚类实验

    实验7 K-means聚类实验 一、实验目的 学习K-means算法基本原理,实现Iris数据聚类。 二、实验内容 应用K-means算法对iris数据集进行聚类。 三、实验结果及分析 0 :输出数据集的基本信息 参考代码在main函数中首先打印了数据、特征名字、目标值、目标值的名字,iris数据集的结果

    2024年02月05日
    浏览(51)
  • 实验二、人工智能:产生式系统(动物识别系统)

    把一组产生式放在一起,让它们互相配合、协同作用,一个产生式生成的结果可以供另一个产生式作为已知事实使用,以求得问题的解,这样的系统成为产生是系统。 产生式系统的例子:动物识别系统 本系统为识别虎、金钱豹、斑马、长颈鹿、企鹅、鸵鸟、信天翁等七种动

    2024年04月14日
    浏览(56)
  • 人工智能导论——遗传算法求解TSP问题实验

    一、实验目的: 熟悉和掌握遗传算法的原理、流程和编码策略,并利用遗传算法求解组合优化问题,理解求解TSP问题的流程并测试主要参数对结果的影响。 二、实验原理: 旅行商问题,即TSP问题(Traveling Salesman Problem)是数学领域中著名问题之一。假设有一个旅行商人要拜

    2023年04月13日
    浏览(45)
  • 人工智能实验:动物识别系统(C++代码实现)

    建立一个动物识别系统的规则库,编写程序用以识别虎、豹、斑马、长颈鹿、企鹅、鸵鸟、信天翁等7种动物。 为了识别这些动物,可以根据动物识别的特征,建立包含下述规则库: R1:if 动物有毛发 then 动物是哺乳动物 R2:if 动物有奶 then 动物是哺乳动物 R3:if 动物有羽毛

    2024年02月03日
    浏览(72)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包