python---A*搜索算法解决八数码问题

问题内容

【八数码问题】
在一个3×3的九宫中有1-8这8个数字以及一个空格随机摆放在其中的格子里。将该九宫格调整到目标状态。
规则:每次只能将与空格(上、下、左、右)相邻的一个数字移动到空格中。试编程实现这一问题的求解。
备注:为了程序中表示方便,用0代替空格。
初始状态和目标状态:均由用户通过键盘手工输入或者从文件读入(不可以写死在程序里面)。

在这里插入图片描述

算法流程

在这里插入图片描述

相关设置

其实和之前的传教士问题的设置差不多,都有用到open表和closed表。

(1)状态用字符串表示 ,如“513708246”;
(2)对状态结点展开所用到的open表和closed表,就用列表 opened=[ ],closed=[ ];
(3)为了保存每一个状态的父结点,使用字典parent={ key:value },key必须不可变,且唯一,和状态的特性相似,value即为每个状态对应的父结点;
(4)为了计算估价函数值,使用Gn={}Fn={},用来存储状态和对应的估价函数值;
(5)这里的估价函数值中的H(n) 是和目标状态相比错位的数目。

关于程序中用到的函数:
THEnum()–用来计算状态的逆序数;
Hn()–用来计算估价函数中的值,即为当前状态和目标状态的错位数;
Expand()–对结点进行拓展;
MIN()–从opened表中选择估价函数值最小的一个状态;
PRINT()–按格式输出结果。

具体程序

本人来自江南大学,同校的小伙伴们记得修改修改,以免查重

# -*- coding: utf-8 -*-
"""
Created on Thu Apr  2 21:58:44 2020

@author:jn
"""
#计算状态对应的逆序数
def THEnum(node):
    Sum=0
    for i in range(1,9):
        num=0
        for j in range(0,i):
          if node[j]>node[i] and node[i]!='0':
              num=num+1
        Sum+=num
    return Sum

#h(n)函数,用于计算估价函数f(n),这里的h(n)选择的是与目标相比错位的数目
def Hn(node):
    global goal
    hn=0
    for i in range(0,9):
        if node[i]!=goal[i]:
            hn+=1
    return hn

#拓展node状态对应的子结点                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
def Expand(node):
    global expand
    tnode=[]
    state = node.index("0")
    elist= expand[state]
    j=state
    for i in elist:
        j=state
        if i>j:
            i,j = j,i
        re= node[:i] + node[j] + node[i+1:j] + node[i] + node[j+1:]
        tnode.append(re)
    return tnode

#将最后的结果按格式输出
def PRINT(result):
    for i in range(len(result)):
            print("step--" + str(i+ 1))
            print(result[i][:3])
            print(result[i][3:6])
            print(result[i][6:])

#选择opened表中的最小的估价函数值对应的状态
def MIN(opened):
    ll={}
    for node in opened:
        k=Fn[node]
        ll[node]=k
    kk=min(ll,key=ll.get)
    return kk
    
#主程序开始
opened=[]
closed=[]
Gn={}#用来存储状态和对应的深度,也就是初始结点到当前结点的路径长度
Fn={}#用来存放状态对应的估价函数值
parent={}#用来存储状态对应的父结点

#expand中存储的是九宫格中每个位置对应的可以移动的情况
#当定位了0的位置就可以得知可以移动的情况
expand = {0:[1, 3], 1:[0, 2, 4], 2:[1, 5],
    3:[0,4,6], 4:[3,1,5,7], 5:[4,2,8],
    6:[3,7],  7:[6,4,8], 8:[7,5]}

start=input("请输入初始状态(从左至右,从上到下,如:102345678):")
goal =input("请输入目标状态(从左至右,从上到下,如:123456780):")

if start==goal:
    print("初始状态和目标状态一致!")
#判断从初始状态是否可以达到目标状态
if (THEnum(start)%2)!=(THEnum(goal)%2):
    print("该目标状态不可达!")
else:
    parent[start]=-1#初始结点的父结点存储为-1
    Gn[start]=0#初始结点的g(n)为0
    Fn[start]=Gn[start]+Hn(start)#计算初始结点的估价函数值
    
    opened.append(start)#将初始结点存入opened表
    while opened:
        current=MIN(opened)#选择估价函数值最小的状态
        del Fn[current]
        opened.remove(current)#将要遍历的结点取出opened表
        
        if current==goal:
            break
        if current not in closed:
            closed.append(current)#存入closed表 
            Tnode=Expand(current)#扩展子结点
            for node in Tnode:
                #如果子结点在opened和closed表中都未出现,则存入opened表
                #并求出对应的估价函数值
                if node not in opened and node not in closed:
                    Gn[node]=Gn[current]+1
                    Fn[node]=Gn[node]+Hn(node)
                    parent[node]=current
                    opened.append(node)
                else:
                    #若子结点已经在opened表中,则判断估价函数值更小的一个路径
                    #同时改变parent字典和Fn字典中的值
                    if node in opened:
                        fn=Gn[current]+1+Hn(node)
                        if fn<Fn[node]:
                            Fn[node]=fn
                            parent[node]=current
    
    result=[]#用来存放路径
    result.append(current)
    while parent[current] != -1:#根据parent字典中存储的父结点提取路径中的结点
        current =parent[current]
        result.append(current)
    result.reverse()#逆序
    PRINT(result)#按格式输出结果

运行结果

在这里插入图片描述

遇到的问题

没遇到什么问题,哈哈哈哈

完结

撒花~~~~~~~~~

  • 53
    点赞
  • 332
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
### 回答1: a*算法是一种启发式搜索算法,可以用于解决八数码问题八数码问题是一种经典的游戏,目标是将一个3*3的九宫格中的数字按照特定顺序排列,其中一个格子为空。每次操作可以将与空格相邻的一个数字移动到空格中,直到达到目标状态。 使用a*算法解决八数码问题主要有以下几个步骤: 1. 定义状态空间:将九宫格中的数字排列看作状态,即每个状态由一个长度为9的数组来表示。 2. 定义启发函数:启发函数用来评估当前状态距离目标状态的距离,通常使用曼哈顿距离或欧几里得距离。在八数码问题中,使用曼哈顿距离计算两个状态之间的距离。 3. 定义操作:定义将一个数字移动到空格中的操作,以及对应的代价。在八数码问题中,每次操作的代价都为1。 4. 使用优先队列存储状态:使用优先队列存储每个状态以及与起始状态的距离 + 启发函数值。 5. 开始搜索:从初始状态开始,每次取出距离 + 启发函数值最小的状态,并对其进行操作,得到一系列可能的下一个状态。将这些状态加入优先队列,并继续搜索,直到找到目标状态。 6. 输出解:当找到目标状态后,可以通过反向遍历得到从目标状态到初始状态的一条路径,即为解。将路径输出即可。 使用Python实现a*算法解决八数码问题具体实现可以参考相教程或代码库。 ### 回答2: 在八数码问题中,有一个3x3的矩阵,其中包含1-8号数字,以及一个空位。基本目标是将矩阵重排、使得排列成指定的形式。 a*算法,是一种基于启发式搜索的算法,它可以在有较大状态空间的问题中找到最优解。在求解八数码问题时,a*算法可以被用来搜索空位所处位置的不同状态,并采用估价函数来判断哪些状态更有可能走向正确的解决方案。 基于估价函数,a*算法被用来搜索状态时已经做好了最小化搜索路径长度的准备,也就是说,它可以尽可能快地找到最优解。 实现a*算法解决八数码问题Python代码,可以分多层解决。首先,需要定义一个函数,用于获取空格的位置。通过该函数,可以确定出当前状况空格往四个方向所能到达的状态。 下一步,需要判断每一个移动后的状态是否合法。移动状态需要计算出一个估价函数的值,来评估该状态是否最有可能走向目标正确状态。 用Python实现时,估价函数可以定义为当前状态离目标状态越远,则评估函数值越大。估价函数的实现可以使用曼哈顿距离来计算两个状态之间的距离。 接下来,通过a*算法进行搜索,直到找到最优解。在算法中,首先通过一个优先级队列(priority queue)来对状态进行排序和筛选。在每一个移动后的状态中,选择估价函数值最小的状态进行搜索。最终,可以找到最优的解决方案。 ### 回答3: A*算法是一种用于路径规划的算法,它能够有效地解决八数码问题八数码问题是指在 3×3 的九宫格中,一个初始状态可以移到目标状态的谜题。在八数码问题中,每个格子可以放置数字1-8或空格,规则是只能上下左右移动,将空格移到目标状态,同时保证空格移动路径最短。 在Python中,构建A*算法解决八数码问题的步骤如下: 1.构建初始的状态和目标状态 定义一个 3 * 3 的列表,用0表示空格,用1-8表示数字。例如,一个样例状态为:[1,2,3,4,5,6,0,7,8]。 2.计算需要移动的步数 通过计算当前状态和目标状态之间不同的数字的个数,即曼哈顿距离(Manhattan distance),来计算出当前状态的评估函数(f(n))。 3.确定移动的方向 向当前空格的周围四个方向依次移动,计算移动后的状态的评估函数f(n)。 4.加入已探索列表 将移动后的状态加入已探索的状态列表中。 5.重复步骤2-4,直到找到目标状态。 如果当前状态和目标状态一致,则搜索结束。否则,重复步骤2-4直到找到目标状态。此时,需要返回最短路径。 6.输出最终答案 输出从初始状态到目标状态的路径。 总体来说,A*算法是一种有效的搜索算法,在处理八数码问题中有着不错的应用效果。在实现A*算法时,要注意选择正确的数据结构和算法实现方法,并严格控制代码的时间复杂度,以提高算法的效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值