如何解决如何在 Python 中为 15-Puzzle 问题实现 IDA* 算法? 参考:
我正在尝试使用 IDA* 算法和曼哈顿启发式算法来解决 15-Puzzle 问题。 我已经从这个维基百科页面 (link) 中的伪代码实现了算法。
这是我目前的代码:
def IDA(initial_state,goal_state):
initial_node = Node(initial_state)
goal_node = Node(goal_state)
threshold = manhattan_heuristic(initial_state,goal_state)
path = [initial_node]
while 1:
tmp = search(path,goal_state,threshold)
if tmp == True:
return path,threshold
elif tmp == float('inf'):
return False
else:
threshold = tmp
def search(path,g,threshold):
node = path[-1]
f = g + manhattan_heuristic(node.state,goal_state)
if f > threshold:
return f
if np.array_equal(node.state,goal_state):
return True
minimum = float('inf')
for n in node.nextnodes():
if n not in path:
path.append(n)
tmp = search(path,g + 1,threshold)
if tmp == True:
return True
if tmp < minimum:
minimum = tmp
path.pop()
return minimum
def manhattan_heuristic(state1,state2):
size = range(1,len(state1) ** 2)
distances = [count_distance(num,state1,state2) for num in size]
return sum(distances)
def count_distance(number,state2):
position1 = np.where(state1 == number)
position2 = np.where(state2 == number)
return manhattan_distance(position1,position2)
def manhattan_distance(a,b):
return abs(b[0] - a[0]) + abs(b[1] - a[1])
class Node():
def __init__(self,state):
self.state = state
def nextnodes(self):
zero = np.where(self.state == 0)
y,x = zero
y = int(y)
x = int(x)
up = (y - 1,x)
down = (y + 1,x)
right = (y,x + 1)
left = (y,x - 1)
arr = []
for direction in (up,down,right,left):
if len(self.state) - 1 >= direction[0] >= 0 and len(self.state) - 1 >= direction[1] >= 0:
tmp = np.copy(self.state)
tmp[direction[0],direction[1]],tmp[zero] = tmp[zero],tmp[direction[0],direction[1]]
arr.append(Node(tmp))
return arr
我正在用 3x3 拼图测试此代码,这是无限循环!由于递归,我在测试代码时遇到了一些麻烦...
我认为错误可能在这里:tmp = search(path,threshold)
(在 search
函数中)。我只在 g 成本值上加了一个。不过应该是正确的,因为我只能将图块移动 1 个位置。
initial_state = np.array([8 7 3],[4 1 2],[0 5 6])
goal_state = np.array([1 2 3],[8 0 4],[7 6 5])
IDA(initial_state,goal_state)
有人可以帮我吗?
解决方法
您的 IDA*
实现中有几个问题。首先,变量path
的目的是什么?我在您的代码中发现了 path
的两个用途:
- 用作标志/地图以保留已访问过的棋盘状态。
- 用作堆栈来管理递归状态。
但是,不可能通过使用单个数据结构同时完成这两项任务。因此,您的代码需要进行的第一次修改:
- 修复 1:将当前
node
作为参数传递给search
方法。 - 修正 2:
flag
应该是一种可以高效执行not in
查询的数据结构。
现在,fix-1 很简单,因为我们可以在搜索方法中将当前访问节点作为参数传递。对于 fix-2,我们需要将 flag
的类型从 list
更改为 set
为:
-
list
对x in s
的平均案例复杂度为:O(n) -
set
的-
x in s
的平均案例复杂度为:O(1) -
x in s
的最坏情况复杂度是:O(n)
-
您可以查看有关 performance for testing memberships: list vs sets 的更多详细信息以了解更多详情。
现在,要将 Node
信息保存到 set
中,您需要在 __eq__
类中实现 __hash__
和 Node
。下面附上修改后的代码。
import timeit
import numpy as np
def IDA(initial_state,goal_state):
initial_node = Node(initial_state)
goal_node = Node(goal_state)
threshold = manhattan_heuristic(initial_state,goal_state)
#print("heuristic threshold: {}".format(threshold))
loop_counter = 0
while 1:
path = set([initial_node])
tmp = search(initial_node,goal_state,threshold,path)
#print("tmp: {}".format(tmp))
if tmp == True:
return True,threshold
elif tmp == float('inf'):
return False,float('inf')
else:
threshold = tmp
def search(node,g,path):
#print("node-state: {}".format(node.state))
f = g + manhattan_heuristic(node.state,goal_state)
if f > threshold:
return f
if np.array_equal(node.state,goal_state):
return True
minimum = float('inf')
for n in node.nextnodes():
if n not in path:
path.add(n)
tmp = search(n,g + 1,path)
if tmp == True:
return True
if tmp < minimum:
minimum = tmp
return minimum
def manhattan_heuristic(state1,state2):
size = range(1,len(state1) ** 2)
distances = [count_distance(num,state1,state2) for num in size]
return sum(distances)
def count_distance(number,state2):
position1 = np.where(state1 == number)
position2 = np.where(state2 == number)
return manhattan_distance(position1,position2)
def manhattan_distance(a,b):
return abs(b[0] - a[0]) + abs(b[1] - a[1])
class Node():
def __init__(self,state):
self.state = state
def __repr__(self):
return np.array_str(self.state.flatten())
def __hash__(self):
return hash(self.__repr__())
def __eq__(self,other):
return self.__hash__() == other.__hash__()
def nextnodes(self):
zero = np.where(self.state == 0)
y,x = zero
y = int(y)
x = int(x)
up = (y - 1,x)
down = (y + 1,x)
right = (y,x + 1)
left = (y,x - 1)
arr = []
for direction in (up,down,right,left):
if len(self.state) - 1 >= direction[0] >= 0 and len(self.state) - 1 >= direction[1] >= 0:
tmp = np.copy(self.state)
tmp[direction[0],direction[1]],tmp[zero] = tmp[zero],tmp[direction[0],direction[1]]
arr.append(Node(tmp))
return arr
initial_state = np.array([[8,7,3],[4,1,2],[0,5,6]])
goal_state = np.array([[1,2,[8,4],[7,6,5]])
start = timeit.default_timer()
is_found,th = IDA(initial_state,goal_state)
stop = timeit.default_timer()
print('Time: {} seconds'.format(stop - start))
if is_found is True:
print("Solution found with heuristic-upperbound: {}".format(th))
else:
print("Solution not found!")
节点:请仔细检查您的 Node.nextnodes()
和 manhattan_heuristic()
方法,因为我在这些方面没有太注意。您可以检查此 GitHub repository 以了解其他算法实现(即 A*
、IDS
、DLS
)以解决此问题。
参考:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。