我正在尝试在Python中进行深度优先搜索,但它无法正常工作。
基本上我们有一个peg-solitaire board:
[1,1,1,1,1,0,1,1,1,1]
1表示挂钩,0表示空位。您必须一次将一个挂钩向后移动一个挂钩或向前移动到一个空位。如果你在这个过程中跳过另一个挂钩,它就变成了一个空槽。你这样做,直到一个钉子仍然存在。所以基本上,游戏就像:
[1, 1, 1, 1, 1, 0, 1, 1, 1, 1]
[1, 1, 1, 0, 0, 1, 1, 1, 1, 1]
[1, 0, 0, 1, 0, 1, 1, 1, 1, 1]
[1, 0, 0, 1, 1, 0, 0, 1, 1, 1]
[1, 0, 0, 0, 0, 1, 0, 1, 1, 1]
[1, 0, 0, 0, 0, 1, 1, 0, 0, 1]
[1, 0, 0, 0, 0, 0, 0, 1, 0, 1] #etc until only 1 peg left
这就是我所拥有的:
class MiniPeg():
def start(self):
''' returns the starting board '''
board = [1,1,1,1,1,0,1,1,1,1]
return board
def goal(self, node):
pegs = 0
for pos in node:
if pos == 1:
pegs += 1
return (pegs == 1) # returns True if there is only 1 peg
def succ(self, node):
pos = 0
for peg in node:
if peg == 1:
if pos < (len(node) - 2): # try to go forward
if node[pos+2] == 0 and node[pos+1] == 1:
return create_new_node(node, pos, pos+2)
if pos > 2: # try to go backwards
if node[pos-2] == 0 and node[pos-1] == 1:
return create_new_node(node, pos, pos-2)
pos += 1
def create_new_node(node, fr, to):
node[fr] = 0
node[to] = 1
if fr > to:
node[fr-1] = 0
else:
node[fr+1] = 0
return node
if __name__ == "__main__":
s = MiniPeg()
b = s.start()
while not s.goal(b):
print b
b = s.succ(b)
所以,现在我的问题:
答案 0 :(得分:9)
在每个步骤从“棋盘位置”“移动”到某个可能的下一个步骤直到达到目标的情况下实现DFS的正常方法如下(伪代码)
seenpositions = set()
currentpositions = set([startingposition])
while currentpositions:
nextpositions = set()
for p in currentpositions:
seenpositions.add(p)
succ = possiblesuccessors(p)
for np in succ:
if np in seenpositions: continue
if isending(np): raise FoundSolution(np)
nextpositions.add(np)
currentpositions = nextpositions
raise NoSolutionExists()
您可能还希望保留向后链接,最后能够发出导致找到解决方案的一系列移动(如果有的话),但这是一个辅助问题。
我不认识您的代码中这种一般结构(或其合理变体)的痕迹。为什么不试着这样记录呢?您只需要编写possiblesuccessors
和isending
代码(如果您坚持将位置保留为列表,则必须将其转换为元组以检查集合中的成员资格并添加到集合中,但是,这是非常小; - )。
答案 1 :(得分:1)
您似乎没有创建新节点,只是重新使用现有节点。 DFS需要某种堆栈(调用堆栈或您自己的堆栈)。那是哪里?
答案 2 :(得分:0)
嗯,首先,深度优先搜索会假设一棵树。现在,这在这里是有意义的,因为在大多数情况下你有几个可能的举动。深度优先搜索将简单地尝试第一次可能的移动,然后是新情况中的第一次可能移动,以及在新情况下的第一次可能移动,直到成功或不再可能移动,在这种情况下它将备份直到它找到了一个没有尝试过的动作,然后再次下降。
这种“正确”的方式是递归。就我所见,你的系统没有递归。
这样的东西会起作用(pythonic psuedo codeish english):
def try_next_move(self, board):
for each of the pegs in the board:
if the peg can be moved:
new_board = board with the peg moved
if new_board is solved:
return True
if self.try_next_move(new_board):
return True
# That move didn't lead to a solution. Try the next.
# No move worked.
return False
答案 3 :(得分:0)
基本的算法问题是succ
函数总是只为给定的板状态产生一个可能的移动。即使存在多个可能的移动,succ
函数也会返回它可以找到的第一个移动。深度优先搜索需要处理每个州的所有可能移动。
其他问题可能来自这样一个事实:create_new_node
虽然名称不实际,但并不真正创建新节点,而是修改现有节点。对于深度优先搜索,您希望保留前一个节点,如果此函数实际创建了它作为参数的列表副本,则会更好。
此外,在succ
检查是否可以向后搜索时,您只会尝试pos > 2
。这太严格了,pos > 1
也没关系。