Python 什么';这是我的BFS实现中8个方块的问题
我设计了一个算法,可以使用BFS或DFS解决8平方问题。当前的问题是,它运行了无限长的时间。如果我让它运行30分钟左右。它以我的RAM满为结束。我的实现中有什么问题。我调试此代码失败。 提前谢谢Python 什么';这是我的BFS实现中8个方块的问题,python,algorithm,data-structures,Python,Algorithm,Data Structures,我设计了一个算法,可以使用BFS或DFS解决8平方问题。当前的问题是,它运行了无限长的时间。如果我让它运行30分钟左右。它以我的RAM满为结束。我的实现中有什么问题。我调试此代码失败。 提前谢谢 import copy import time import pprint def get_empty_board(): return [ [7,4,2], [8,3,0], [1,5,6] ] end_state = [
import copy
import time
import pprint
def get_empty_board():
return [
[7,4,2],
[8,3,0],
[1,5,6]
]
end_state = [
[1,2,3],
[8,0,4],
[7,6,5]
]
def solve_squares(board):
states_explored = list()
states = [ (neighbor,[board] + [neighbor]) for neighbor in get_neighbors(board) ]
while states:
print(len(states))
current_state = states.pop(0)
if (current_state[0]) in states_explored:
continue
# if len(states) > 300:
# states =[ states[0] ]
# pprint.pprint(current_state)
# pprint.pprint(current_state)
if current_state[0] == end_state:
return True,current_state[1]
neighbors = get_neighbors(current_state[0])
states_explored.append(current_state[0])
for neighbor in neighbors:
if (neighbor) not in states_explored:
states.append((neighbor,current_state[1] + [neighbor]))
states_explored.append((neighbor[0]))
return False,None
def get_neighbors(board):
x = None
y = None
neighbors = list()
for i in range(len(board)):
for j in range(len(board[0])):
if board[i][j] == 0:
x = i
y = j
break
# print(x,y)
for i in range(len(board)):
for j in range(len(board[0])):
if abs(i-x) <= 1 and abs(j-y) <= 1:
if abs(i-x) != abs(j-y):
# print(i,j)
new_state = copy.deepcopy(board)
new_state[x][y] = new_state[i][j]
new_state[i][j] = 0
# pprint.pprint(new_state)
# time.sleep(5)
neighbors.append(new_state)
return neighbors
def main():
result,path = solve_squares(get_empty_board())
print(result)
print(path)
main()
导入副本
导入时间
导入pprint
def get_empty_board():
返回[
[7,4,2],
[8,3,0],
[1,5,6]
]
结束状态=[
[1,2,3],
[8,0,4],
[7,6,5]
]
def解算方格(板):
州=列表()
states=[(邻居,[board]+[neighbor])表示get_邻居(board)]
而缔约国:
印刷品(国家)
当前状态=states.pop(0)
如果(当前_状态[0])处于_探索状态:
持续
#如果len(状态)>300:
#州=[州[0]]
#pprint.pprint(当前状态)
#pprint.pprint(当前状态)
如果当前\u状态[0]==结束\u状态:
返回True,当前_状态[1]
邻居=获取邻居(当前状态[0])
states\u explored.append(当前\u状态[0])
对于邻居中的邻居:
如果(邻居)未处于以下状态:
states.append((邻居,当前_状态[1]+[邻居])
states_.append((邻居[0]))
返回False,无
def get_邻居(板):
x=无
y=无
邻居=列表()
对于范围内的i(len(board)):
对于范围内的j(len(板[0]):
如果板[i][j]==0:
x=i
y=j
打破
#打印(x,y)
对于范围内的i(len(board)):
对于范围内的j(len(板[0]):
如果abs(i-x)您的解决方案中需要进行两项改进:
您正在使用python列表(例如,states\u explored
)跟踪您已经访问过的电路板配置。现在,s中x的列表的平均大小写复杂度为:O(n)。为此,您需要应用一些有效的数据结构(例如,set
)。您可以查看有关此优化的详细讨论
您的RAM已满,因为您正在队列中存储每个发现的板配置的完整路径(例如,状态
)。这是非常不必要的,而且内存效率低下。为了解决这个问题,您可以使用有效的数据结构(例如,map
)来存储给定状态的父状态。发现目标后,需要通过回溯地图来构建路径
我们可以通过下面的示例来可视化第二次优化。比方说,您正在将
映射为键值:
<initial-state, NaN>
<state-1, initial-state>
<state-2, state-1>
<state-3, state-2>
...
...
<final-state, state-n>
...
...
现在,在发现final state
之后,我们可以在地图中查询final state
的父级是什么。然后,递归地进行此查询,直到到达初始状态
如果您应用这两种优化,您将在运行时和内存消耗方面获得巨大的改进。解决方案中需要几项改进:
您正在使用python列表(例如,states\u explored
)跟踪您已经访问过的电路板配置。现在,s中x的列表的平均大小写复杂度为:O(n)。为此,您需要应用一些有效的数据结构(例如,set
)。您可以查看有关此优化的详细讨论
您的RAM已满,因为您正在队列中存储每个发现的板配置的完整路径(例如,状态
)。这是非常不必要的,而且内存效率低下。为了解决这个问题,您可以使用有效的数据结构(例如,map
)来存储给定状态的父状态。发现目标后,需要通过回溯地图来构建路径
我们可以通过下面的示例来可视化第二次优化。比方说,您正在将
映射为键值:
<initial-state, NaN>
<state-1, initial-state>
<state-2, state-1>
<state-3, state-2>
...
...
<final-state, state-n>
...
...
现在,在发现final state
之后,我们可以在地图中查询final state
的父级是什么。然后,递归地进行此查询,直到到达初始状态
如果您应用这两种优化,您将在运行时以及内存消耗方面获得巨大的改进。问题确实是性能。要了解速度,请在代码中输入以下print
(仅此一项):
您将看到它是如何随着进程而减慢的。我编写了一个更高效的实现,发现该算法需要访问100000多个州才能找到解决方案。按照您看到上述行输出行的速度,您可以想象需要很长时间才能完成。我没有耐心等它
请注意,我在您的代码中发现了一个错误,但它不会损害算法:
states_explored.append((neighbor[0]))
这种说法是错误的,原因有二:
neighbor
是一块板,因此从中获取索引[0]
,将生成该板的第一行,而这对该算法是无用的
- 如果您将其更正为仅
邻居
,它将变得重要,但会停止算法的运行,因为当这些邻居从队列中弹出时,搜索将停止
所以这一行应该省略
以下是一些提高算法效率的方法:
states_explored.append((neighbor[0]))
- 使用原语值表示电路板,而不是列表。例如,一个9个字符的字符串就可以完成这项工作。Python处理字符串的速度比处理二维列表的速度快得多。这也意味着您不需要
deep\u copy
- 不要使用列表跟踪已访问的状态。使用一套——或者也包括下一点——措辞
# move mapping (based on position of the zero/empty block)
moves = { 0: [1,3],
1: [0,2,4],
2: [1,5],
3: [0,4,6],
4: [1,3,5,7],
5: [2,4,8],
6: [3,7],
7: [4,6,8],
8: [5,7] }
from collections import deque
def solve(board,target=(1,2,3,4,5,6,7,8,0)):
if isinstance(board[0],list): # flatten board
board = tuple(p for r in board for p in r)
if isinstance(target[0],list): # flatten target
target = tuple(p for r in target for p in r)
seen = set()
stack = deque([(board,[])]) # BFS stack with board/path
while stack:
board,path = stack.popleft() # consume stack breadth first
z = board.index(0) # position of empty block
for m in moves[z]: # possible moves
played = list(board)
played[z],played[m] = played[m],played[z] # execute move
played = tuple(played) # board as tuple
if played in seen: continue # skip visited layouts
if played == target: return path + [m] # check target
seen.add(played)
stack.append((played,path+[m])) # stack move result
initial = [ [7,4,2],
[8,3,0],
[1,5,6]
]
target = [ [1,2,3],
[8,0,4],
[7,6,5]
]
solution = solve(initial,target) # runs in 0.19 sec.
# solution = (flat) positions of block to move to the zero/empty spot
[4, 1, 0, 3, 6, 7, 4, 1, 0, 3, 4, 1, 2, 5, 8, 7, 6, 3, 4, 5, 8, 7, 4]
board = [p for r in initial for p in r]
print(*(board[i:i+3] for i in range(0,9,3)),sep="\n")
for m in solution:
print(f"move {board[m]}:")
z = board.index(0)
board[z],board[m] = board[m],board[z]
print(*(board[i:i+3] for i in range(0,9,3)),sep="\n")
[7, 4, 2]
[8, 3, 0]
[1, 5, 6]
move 3:
[7, 4, 2]
[8, 0, 3]
[1, 5, 6]
move 4:
[7, 0, 2]
[8, 4, 3]
[1, 5, 6]
move 7:
[0, 7, 2]
[8, 4, 3]
[1, 5, 6]
move 8:
[8, 7, 2]
[0, 4, 3]
[1, 5, 6]
move 1:
[8, 7, 2]
[1, 4, 3]
[0, 5, 6]
move 5:
[8, 7, 2]
[1, 4, 3]
[5, 0, 6]
move 4:
[8, 7, 2]
[1, 0, 3]
[5, 4, 6]
move 7:
[8, 0, 2]
[1, 7, 3]
[5, 4, 6]
move 8:
[0, 8, 2]
[1, 7, 3]
[5, 4, 6]
move 1:
[1, 8, 2]
[0, 7, 3]
[5, 4, 6]
move 7:
[1, 8, 2]
[7, 0, 3]
[5, 4, 6]
move 8:
[1, 0, 2]
[7, 8, 3]
[5, 4, 6]
move 2:
[1, 2, 0]
[7, 8, 3]
[5, 4, 6]
move 3:
[1, 2, 3]
[7, 8, 0]
[5, 4, 6]
move 6:
[1, 2, 3]
[7, 8, 6]
[5, 4, 0]
move 4:
[1, 2, 3]
[7, 8, 6]
[5, 0, 4]
move 5:
[1, 2, 3]
[7, 8, 6]
[0, 5, 4]
move 7:
[1, 2, 3]
[0, 8, 6]
[7, 5, 4]
move 8:
[1, 2, 3]
[8, 0, 6]
[7, 5, 4]
move 6:
[1, 2, 3]
[8, 6, 0]
[7, 5, 4]
move 4:
[1, 2, 3]
[8, 6, 4]
[7, 5, 0]
move 5:
[1, 2, 3]
[8, 6, 4]
[7, 0, 5]
move 6:
[1, 2, 3]
[8, 0, 4]
[7, 6, 5]