# 描述
# 在九宮格里放在1到8共8個數字還有一個是空格,與空格相鄰的數字可以移動到空格的位置,問給定的狀態最少需要幾步能到達目標狀態(用0表示空格):
# 1 2 3
# 4 5 6
# 7 8 0
#
# 輸入
# 輸入一個給定的狀態。
#
# 輸出
# 返回True 或 False
1.BFS
首先定義存儲“狀態”的結點
from copy import deepcopy
import numpy as np
class Node:
def __init__(self, state, parent, operator):
self.state = state
self.parent = parent
self.operator = operator
def operate(self, dir): # 返回算符變換后的新節點
new_state = move0(self.state, dir)
if new_state == False:
return None
else:
return Node(new_state, self, dir) # 以self為父
def traverse(self):
cur = self
res = []
while cur is not None:
print(cur.state)
res.append(cur)
cur = cur.parent
return res
def depth(self):
return len(self.traverse()) - 1
兩個輔助函數
def pprint(arr):
print(np.array(arr))
def find0(state): # 在state中尋找0的位置
for i in range(len(state)):
for j in range(len(state)):
if state[i][j] == 0:
ind0 = [i, j]
return ind0
定義操作算符,向direction方向移動空格0,並返回新的狀態
dirs = ['up', 'down', 'left', 'right']
def move0(state, direction): # state當前狀態,2d list,dir為0的移動方向
state1 = deepcopy(state)
ind0 = find0(state1)
x, y = ind0[0], ind0[1] # 0的當前位置
if direction == 'up':
if x == 0:
return False
else:
tempind = [x-1, y] # 待交換的位置
# state[x][y], state[x-1,y] = state[x-1][y], state[x][y]
state1[x][y] = state1[x - 1][y]
state1[x - 1][y] = 0
# print(state)
elif direction == 'down':
if x == len(state1) - 1: # 如果x在最后一行
return False
else:
tempind = [x+1, y]
state1[x][y] = state1[x + 1][y]
state1[x + 1][y] = 0
elif direction == 'left':
if y == 0:
return False
else:
tempind = [x, y-1]
state1[x][y] = state1[x][y - 1]
state1[x][y - 1] = 0
elif direction == 'right':
if y == len(state1) - 1:
return False
else:
tempind = [x, y+1]
state1[x][y] = state1[x][y + 1]
state1[x][y + 1] = 0
return state1
以下是寬度優先搜索BFS函數,bfs是我自己寫的,bfs1是按書上的節點定義寫的
stack = []
def bfs(state,goal): # 不定義結點的版本
open = []
closed = []
open.append(state)
while True:
print(f'open: {len(open)}')
if not open: # open為空
return False
n = open.pop(0) # 隊列先進先出fifo, n為open表中第一個結點
closed.append(n)
for dir in dirs:
next_state = move0(n, dir)
if next_state is not False and next_state not in closed: # 下一個狀態在狀態空間內且未被搜索過
open.append(next_state)
if next_state == goal:
pprint(next_state)
return True
pprint(next_state)
print()
def bfs1(init_state,goal): # 按照書上的節點定義
open = []
closed = []
init_node = Node(init_state, None, None)
open.append(init_node)
while True:
if not open: # open是空表
return False
node = open.pop(0) # 把第一個節點node彈出
closed.append(node) # 將node放入closed表
for dir in dirs:
node_new = node.operate(dir)
if node_new is not None and node_new not in closed: # 下一個狀態在狀態空間內且未被搜索過
open.append(node_new)
if node_new.state == goal:
pprint(node_new.state)
nodelist = node_new.traverse()
nodelist.reverse()
print()
[(print(node.operator), pprint(node.state)) for node in nodelist]
return True
pprint(node_new.state)
print()
舉例測試
goal = [[1, 2, 3],
[8, 0, 4],
[7, 6, 5]]
init = [[2,8,3],
[1,0,4],
[7,6,5]]
if __name__ == '__main__':
print(bfs1(init,goal))
"""
out:
None
[[2 8 3]
[1 0 4]
[7 6 5]]
up
[[2 0 3]
[1 8 4]
[7 6 5]]
left
[[0 2 3]
[1 8 4]
[7 6 5]]
down
[[1 2 3]
[0 8 4]
[7 6 5]]
right
[[1 2 3]
[8 0 4]
[7 6 5]]
True
"""
2.DFS
def dfs(init_state, goal):
initnode = Node(init_state, None, None) # 初始結點
open = [] # 棧, 已探索但未展開的結點
closed = []
open.append(initnode)
while True:
if not open: # 若open為空
print('此初始狀態無法完成搜索。')
return False
curnode = open.pop()
closed.append(curnode.state)
if curnode.depth() > 5:
continue
for dir in dirs:
node = curnode.operate(dir)
if node is not None and node.state not in closed: # node在狀態空間內,且未被探索過
open.append(node)
if node.state == goal: # 已搜索到
print('搜索成功。')
# print(node.state, goal)
nlist = node.traverse()
nlist.reverse()
# print(nlist)
for n in nlist: # 輸出
# print(n)
print(n.state) if n.operator is None else print(n.operator, n.state)
return True
print(node.state)
總結:DFS與BFS的唯一區別在於,DFS的open表是棧,而BFS的open表為隊列