首先介绍一下A星搜索算法,他是一种启发式搜索算法。
对于A星搜索算法的具体原理等此处我就不介绍,可以查看A星搜索算法原理-百度百科
在查看相关资料的时候发现对于A星搜索算法往往给出的都是原理的介绍,对于伪代码许多具体的文章都没有给出,为了使后面编写解题代码更加清晰,此处我给出A星搜索的伪代码
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 **********#
难度不是很大,但我调试了很久,有的情况是无解的,因此在选测试样例的时候注意调整