我正在尝试解决OCaml中的拼图游戏。我几乎做了所有事情..除了程序的核心功能,深度优先搜索功能。 这就是我现在的功能:
let df_search_path (Graph next) start =
let rec from_node visited a =
print(a);
if List.mem a visited then raise Fail
else if goal(a) then [a]
else a::from_list (a::visited) (next a)
and from_list visited nextA = match visited with
[] -> raise Fail
| nextA::rest -> try from_node visited nextA
with Fail -> from_list visited rest
in from_node [] start;;
Graph
是一个图表,next
是一个搜索2,3或4个下一步移动的函数(我移动空白区域),goal
是一个检查是否为函数的函数当前a
状态是目标,Fail
是正常例外。
我尝试了很多其他功能,但效果很好。
这个函数无休止的循环始终处于起始状态,我无法理解为什么。
print
是一个以友好形式打印状态a
的自定义函数。
我做错了什么?我正在使用远离解决方案的状态“1移动”进行测试,只需“下移”即可解决此问题..但它仍处于第一状态,始终打印启动配置!
答案 0 :(得分:4)
我怀疑您的错误只是match visited with ..
而不是match nextA with ...
中的from_list
。
let df_search_path (Graph next) start =
let rec from_node visited a =
print(a);
if List.mem a visited then raise Fail
else if goal(a) then [a]
else a::from_list (a::visited) (next a)
and from_list visited nextA = match nextA with
| [] -> raise Fail
| nextA::rest -> try from_node visited nextA
with Fail -> from_list visited rest
in from_node [] start;;
也就是说,还有其他方法可以改进代码:目前,“访问”只存储通过此搜索路径访问的节点,而不是存储到目前为止访问的所有节点;移动到全局保留并在任何节点的所有“子搜索”之间共享的数据结构将减少无用搜索的数量(如果您只想要一条通向目标的路径)。
最后,在这里使用列表是一个相当糟糕的主意,因为List.mem
需要时间线性的列表大小;这给出了整体二次行为。您应该使用专门用于成员资格检查的数据结构,例如Set
(或者可能是与您的问题域相对应的数据结构:例如,在类似迷宫的搜索中,布尔矩阵通常更简单,更高效)
答案 1 :(得分:2)
很难确切地看到这段代码应该如何工作。这是我看到的东西:
您使用next a
计算要访问(显示)的节点列表。在from_list
函数中,您不使用此列表。相反,您将visited
列表的第一个元素重命名为nextA
并重新访问它。您似乎只是一遍又一遍地重新访问第一个已访问过的节点。我不明白为什么from_list
会关心所访问的节点。很可能它只是将列表传递给from_node
。