不能在OCaml做回溯研究

时间:2013-02-03 15:26:37

标签: search ocaml backtracking depth

我正在尝试解决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移动”进行测试,只需“下移”即可解决此问题..但它仍处于第一状态,始终打印启动配置!

2 个答案:

答案 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