Python八数码问题A*算法

本文深入探讨了A*算法在解决八数码问题中的应用与实现过程,详细介绍了A*算法的核心概念、核心实现步骤以及具体代码解析。通过实例演示,展示了如何利用A*算法高效地寻找最优解路径,特别强调了估价函数h(x)的选择对算法性能的影响。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、A*算法概述    

        A*(A-Star)算法是一种静态路网中求解最短路最有效的方法。公式表示为:

f(n)=g(n)+h(n)

        其中f(n) 是从初始点经由节点n到目标点的估价函数g(n) 是在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。保证找到最短路径(最优解的)条件,关键在于估价函数h(n)的选取:

        估价值h(n)<=n到目标节点的距离实际值,这种情况下,搜索的点数多,搜索范围大,效率低。但能得到最优解。如果 估价值>实际值, 搜索的点数少,搜索范围小,效率高,但不能保证得到最优解。


二、核心实现介绍

1.  h(x)估算函数:

#计算给定节点array的估价函数h(x)

def fore_hs(array, target) :

    hs= 0

    fori in range(0, 9) :

       if array[i] != target[i] :

           hs += 1

   return hs

2.  产生新节点并更新估算权值:

#从father节点产生一个新的节点,要求计算出估价函数

def insert_s(t_open, t_close, a_new,a_target, s_father) :

   del_none(t_open)

   del_none(t_close)

   cost = s_father.get_gs()+1 + fore_hs(a_new, a_target)

   if  not judge_repeat(t_open,t_close, a_new, cost) :

       return None

   s_new = state(a_new, s_father)

   s_new.set_cost(s_father.get_gs()+1, fore_hs(a_new, a_target))

   return s_new

三、结果截图


四、代码

# filename :chess.py
# info: A*算法求解八数码问题
class state :
    def __init__(self, array, father_state) :
        self.array = array
        self.gs = 0#从初始节点S0到节点n的实际代价
        self.hs = 0#从节点n到目标节点Sg的最优路径代价
        self.close_flag = False #是否放入close表
        self.father_state = father_state#此节点的父节点
    def get_array(self) :
        return self.array
    def get_father(self) :
        return self.father_state
    def get_gs(self) :
        return self.gs    
    def get_hs(self) :
        return self.hs
    def set_cost(self, gs, hs) :
        self.gs = gs
        self.hs = hs
    def print_a(self) :
        print('array: ', self.array, '\n       gs: ', self.gs, '   hs: ', self.hs)
        
#将start位置和end位置的数字交换,并返回新的array
def move(array, start, end) :
    a_tmp = array[:]
    tmp = array[start]
    a_tmp[start] = a_tmp[end]
    a_tmp[end] = tmp
    return a_tmp

#计算给定节点array的估价函数h(x)
def fore_hs(array, target) :
    hs = 0
    for i in range(0, 9) :
        if array[i] != target[i] :
            hs += 1
    return hs

#用于open表中节点按gs+hs排序
def sor_key(t_sor) :
    return t_sor.get_gs() + t_sor.hs

#用于根据close表得到求解路径
def get_path(t_close) :
    s_tmp = t_close[len(t_close)-1]
    t_tmp1 = []
    t_tmp2 = []
    while(not s_tmp==None) :
        t_tmp1.append(s_tmp)
        s_tmp = s_tmp.get_father()
    for i in range(0, len(t_tmp1)) :
        t_tmp2.append(t_tmp1[len(t_tmp1)-i-1])
    for i in t_tmp2 :
        i.print_a()
    return t_tmp2

#删除某节点的子节点(递归删除)
def del_child(s_father) :
    for i in [k for k in t_open if k.get_father() == s_father] :
        del_child(i)
        del t_open[t_open.index(i)]
    for j in [k for k in t_open if k.get_father() == s_father] :
        del_child(j)
        del t_open[t_open.index(j)]

#判断节点是否重新出现,并对重新出现节点进行处理
def judge_repeat(t_open, t_close, a_new, cost) :
    #若在open表中出现,并且新插入位置的代价比原代价小,则可以删除原节点,在新位置插入
    if (not t_open == None) and (not t_open == []) :
        for i in t_open :
            if a_new==i.get_array() :                                                   
                if cost >= (i.get_gs() + i.get_hs()) :
                    return False
                else :
                    del t_open[t_open.index(i)]
                    return True#需要重新插入
    # 若重复节点出现在close表中,可以改变其父节点,并删除子节点(重新求取)
    if (not t_close == None) and (not t_close == []) :
        for i in t_close :
            if a_new==i.get_array() :
                if cost >= (i.get_gs() + i.get_hs()) :
                    return False
                else :
                    del_child(i)
                    del t_open[t_open.index(i)]
                    return True#需要重新插入
    return True
#删除table中的None节点
def del_none(table) :
    if (not table==None) and (not table==[]) :
        if table[len(table)-1]==None :
            table = table[:table.index(None)]

#从father节点产生一个新的节点,要求计算出估价函数
def insert_s(t_open, t_close, a_new, a_target, s_father) :
    del_none(t_open)
    del_none(t_close)
    cost = s_father.get_gs()+1 + fore_hs(a_new, a_target)
    if  not judge_repeat(t_open, t_close, a_new, cost) :
        return None
    s_new = state(a_new, s_father)
    s_new.set_cost(s_father.get_gs()+1, fore_hs(a_new, a_target))
    return s_new

#用于拓展open表中current节点
def expand(t_open, t_close, s_current, a_target) :
    index = s_current.get_array().index(-1)#获得空位置
    move_table = {0: [[0,1], [0,3]],
             1: [[1, 0], [1, 2], [1, 4]],
             2: [[2, 1], [2, 5]],
             3: [[3, 0], [3, 4], [3, 6]],
             4: [[4, 1], [4, 3], [4, 5], [4, 7]],
             5: [[5, 2], [5, 4], [5, 8]],
             6: [[6, 3], [6, 7]],
             7: [[7, 4], [7, 6], [7, 8]],
             8: [[8, 5], [8, 7]]}
    for key, value in move_table.items() :
        if index == key :
            for i in value :
                s_tmp = insert_s(t_open, t_close, move(s_current.get_array(), i[0], i[1]), a_target, s_current)
                if not s_tmp == None :
                    t_open.append(s_tmp)

#a--array表示节点中数的排列, t--table表示表, s--state表示节点
def answer(start) :
    a_start = start
    a_target = [1, 2, 3,
                8, -1, 4,
                7, 6, 5]
    #节点s0放入open表
    s_tmp = state(a_start, None)
    s_current = s_tmp
    s_tmp.set_cost(0, fore_hs(a_start, a_target))
    t_open = [s_tmp]
    t_close  = []
    while(True) :
        #若open表为空则无解退出
        if t_open==None or t_open==[] :
            print("can't find the path.")
            return
        #将open表元素排序
        t_open = sorted(t_open, key = sor_key)
        t_close.append(t_open[0])
        s_current = t_open[0]
        del t_open[0]
        #print('insert close.')
        #若节点n为目标节点则结束,返回路径
        if  a_target == s_current.get_array() :
            print("Find it!")
            return get_path(t_close)
        #拓展s_current节点  
        expand(t_open, t_close, s_current, a_target)#拓展节点函数
        #print('2: ', t_open)

if __name__=='__main__' :
    print('test 1 :')
    answer([2, 8, 3, 1, -1, 4, 7, 6, 5])
    print('\n\ntest 2 :')
    answer([2, 8, 3, 1, 6, 4, 7, -1, 5])
    print('\n\ntest 3 :')
    answer([2, 3, -1, 1, 8, 4, 7, 6, 5])
    print('\n\ntest 4 :')
    answer([2, 8, 3, 1, 4, 5, -1, 7, 6])
    #print('\n\ntest 4 :')
    #answer([5, 3, 7, 6, 1, -1, 2, 8, 4])


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值