八数码问题--A星算法Python实现

首先介绍一下A星搜索算法,他是一种启发式搜索算法。
对于A星搜索算法的具体原理等此处我就不介绍,可以查看A星搜索算法原理-百度百科

A星搜索算法伪代码

在查看相关资料的时候发现对于A星搜索算法往往给出的都是原理的介绍,对于伪代码许多具体的文章都没有给出,为了使后面编写解题代码更加清晰,此处我给出A星搜索的伪代码

数据结构以及相关函数介绍

  • open
    open是一个列表,其中储存的是待访问的节点,类似于BFS中的邻接点组成的列表,不过后面在选取下一个访问节点的时候需要按照估价函数值最小的节点进行访问。
  • closed
    closed也是列表,其中存储的是已经访问的节点。
  • 估价函数
    估价函数是A星算法启发式的一个重要由来,其由两个部分组成一个是G值其记录的是已用的代价,另一个是H值其是当前节点到目标节点的估计值

算法伪代码

new openList;
new closeList;
openList.add(start); // 把起始节点加入openList
loop{
	current = lowest f cost in openList;
	if(currentNode == end) return; // 找到路线结束
	foreach(neighbour in currentNode.Neighbours){
	if(closeList.Contains(neighbor(neighbor)
	 or neigbor == obstacle) continue;
	// 对于已访问节点或者障碍物节点则跳过
	if(newfCost <= oldfCost ||!openList.Contains(neighbour)){
		// 若不在open中或者新的计算出的花费小于旧的就对其估计函数值以及亲子关系
		neighbour.fCost = newfCost;
		neighbour.parent = currentNodel
	if(!openList.Contains(neighbour)){
		// 不在open列表中
		openList.Add(neighbour);
		}
	}
}

八数码问题

在这里插入图片描述
八数码问题也叫九宫问题,是人工智能中状态搜索中的经典问题,其中,该问题描述为:在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。

问题分析

此题用搜索算法比如广度优先等都能实现其实。关键是将字符串抽象为一个一个状态,同时确定估价函数的计算方式。

求解代码

# -*- coding:utf-8 -*-

class Node:  # 定义状态节点
    def __init__(self, state, parent, G, H, index, action):
        self.state = state
        self.parent = parent
        self.G = G
        self.H = H
        self.action = action
        self.index = index  # 记录空格的位置


class Solution:
    def salvePuzzle(self, init, targ):
        ''' 求解8数码问题
        参数:
        init - 初始状态 例如'123046758'
        targ - 目标状态 均为'012345678'
        返回值:
        clf - 由udlr组成的移动路径字符串
        '''
        # 请在这里补充代码,完成本关任务
        # ********** Begin **********#
        move_action = [(-1,0), (1,0), (0,1), (0,-1)]
        open_List = list()
        closed_list = list()
        open_List_state = set()
        close_List_state = set()
        F = {}
        start = Node(init, 0, 0, self.calcDistH(init, targ),init.find("0"),"0")
        F[init] = start.H+start.G
        open_List_state.add(init)
        open_List.append(start)
        action = {
            (-1,0):"l",
            (1,0):"r",
            (0,1):"d",
            (0,-1):"u"
        }
        while len(open_List) > 0:  # 当openList不为空则继续循环
            node = min(open_List, key=lambda x: x.H + x.G)
            #print(node.H+node.G,node.G,node.state)
            if node.state == targ: # 说明遍历到终点
                path = []
                current_node = node
                while current_node !=0:
                    path.append(current_node.action)
                    current_node = current_node.parent
                return "".join(path[-2::-1])
            for step in move_action:
                x = (node.index)%3
                y = int((node.index)/3)
               # print(x, y)
                x += step[0]
                y+=step[1]

                if x>=0 and y>=0 and x<3 and y<3:
                    if step == (0, -1):
                        print(x, y)
                    new_state = self.moveMap(node.state, node.index, node.index + 3*step[1]+step[0])
                   # print(new_state,node.index,node.state)
                    H = self.calcDistH(new_state, targ)
                    if new_state in close_List_state:
                        continue
                    if new_state not in open_List_state or F[new_state] > node.G+1+H:
                        new_node = Node(new_state,node,node.G+1,H,node.index + 3*step[1]+step[0],action[step])
                        F[new_state] = node.G+1+H
                        if new_state in open_List_state:
                            for n in open_List:
                                if n.state == new_state:
                                    open_List.remove(n)
                        open_List.append(new_node)
            open_List.remove(node)
            closed_list.append(node)
            close_List_state.add(node.state)
        # ********** End **********#

    def calcDistH(self, src_map, dest_map):
        '''启发式函数h(n)
        参数:
        src_map  - 当前8数码状态
        dest_map - 目标8数码状态
        返回值:
        clf - 当前状态到目标状态的启发式函数值
        '''
        # 请在这里补充代码,完成本关任务
        # ********** Begin **********#
        h = 0
        for i in range(len(src_map)):
            h += abs(int(src_map[i]) - int(dest_map[i]))
        return h
        # ********** End **********#

    def moveMap(self, cur_map, i, j):
        '''状态转换(交换位置i和j)
        参数:
        cur_map - 当前8数码状态
        i - 当前8数码状态中空格0的位置索引
        j - 将空格0的位置i移动到位置j,位置j移动到位置i
        返回值:
        clf - 新的8数码状态
        '''

        # 请在这里补充代码,完成本关任务
        # ********** Begin **********#
        map = list(cur_map)
        temp = map[i]
        map[i] = map[j]
        map[j] = temp
        return "".join(map)
        # ********** End **********#

解析

难度不是很大,但我调试了很久,有的情况是无解的,因此在选测试样例的时候注意调整

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值