使用OCaml中的memoization解决序列对齐无法得到正确的答案

时间:2014-10-13 19:09:15

标签: dynamic recursion ocaml dynamic-programming memoization

我使用Hashtbl存储(int*string*string),这是问题的答案。但是,当我运行答案是不正确的。我认为它正在跳过一些值并且没有计算它们。

这是我的代码:

let solve_memo (x:string) (y:string) : (int*string*string)  =
    let x_len = String.length x in
    let y_len = String.length y in
    let tbl_size = x_len * y_len in
    let tbl = Hashtbl.create tbl_size in
    let case1 xi yi =
        if x.[xi] = y.[yi] then 1 else -1
    in
    let choose_max (pt1,strxi,stryi) (pt2,strx2,stry2) (pt3,strx3,stry3) =
        if pt1>pt2 then
            if pt1>pt3 then (pt1,strxi,stryi)
            else (pt3,strx3,stry3)
        else 
            if pt2>pt3 then (pt2,strx2,stry2) 
            else (pt3,strx3,stry3)
    in
    let rec aux xi yi (pt,strx,stry) =
    if (xi = x_len && yi = y_len) then (pt,strx,stry)
    else
    if xi = x_len then 
        (
            pt + (-2 * (y_len - yi)),
            String.concat "" [strx; String.make (y_len - yi) ' '],
            String.concat "" [stry; String.sub y (yi) (y_len - yi)]
        )
    else if yi = y_len then
        (pt + (-2 * (x_len - xi)),
        String.concat "" [strx; String.sub x (xi) (x_len - xi)],
        String.concat "" [stry; String.make (x_len - xi) ' ']
        )
    else 
        try
        Hashtbl.find tbl (xi,yi)
        with _ ->
        let r1 = aux (xi+1) (yi+1) (pt+(case1 xi yi), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; Char.escaped y.[yi]]) in
        let r2 = aux (xi+1) yi ((pt-2), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; " "]) in
        let r3 = aux xi (yi+1) ((pt-2), String.concat "" [strx; " "] , String.concat "" [stry; Char.escaped y.[yi]]) in
        let r = choose_max r1 r2 r3 in
        let _ = Hashtbl.add tbl (xi,yi) r in
        r
in aux 0 0 (0,"","")
;;

当我打印在hashtbl中找到的值时,它会重复2-3次可能在迭代开始时创建的值。 谢谢。

ADD:

这是原始的天真求解函数,我想添加一个Hashtbl来使它更快但它返回错误的结果

let solve (x:string) (y:string) : (int*string*string)  =
let x_len = String.length x in
let y_len = String.length y in
let rec aux xi yi (pt,strx,stry) =
let case1 xi yi =
    if x.[xi] = y.[yi] then 1 else -1
    in
    let choose_max (pt1,strxi,stryi) (pt2,strx2,stry2) (pt3,strx3,stry3) =
        if pt1>pt2 then
            if pt1>pt3 then (pt1,strxi,stryi)
            else (pt3,strx3,stry3)
        else 
            if pt2>pt3 then (pt2,strx2,stry2) 
            else (pt3,strx3,stry3)
    in
    if xi = x_len then 
        (
            pt + (-2 * (y_len - yi)),
            String.concat "" [strx; String.make (y_len - yi) ' '],
            String.concat "" [stry; String.sub y (yi) (y_len - yi)]
        )
    else if yi = y_len then
        (pt + (-2 * (String.length x - xi)),
        String.concat "" [strx; String.sub x (xi) (x_len - xi)],
        String.concat "" [stry; String.make (x_len - xi) ' ']
        )
    else
        let r1 = aux (xi+1) (yi+1) (pt+(case1 xi yi), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; Char.escaped y.[yi]]) in
        let r2 = aux (xi+1) yi ((pt-2), String.concat "" [strx; Char.escaped x.[xi]] , String.concat "" [stry; " "]) in
        let r3 = aux xi (yi+1) ((pt-2), String.concat "" [strx; " "] , String.concat "" [stry; Char.escaped y.[yi]]) in
        choose_max r1 r2 r3
in aux 0 0 (0,"","")
;;

1 个答案:

答案 0 :(得分:0)

我认为您无法轻松修改此函数以获取用于记忆的hashtbl。这是因为您将累加器(pt,strx,stry)从三个不同的方向((xi,yi) .. n0传递给单元格n2(累加器表示子序列的对齐),下图)。在与序列的其余部分(r0..r2)对齐之前,您尚未确定三者中的哪一个是最佳的。

alignment

通过添加memoization,你只存储一个这样的调用的结果,而不是最好的。因此,您的结果取决于先前的单元格(来自n0..n2的累加器)以及对序列其余部分r0..r2的最佳对齐的恢复。因此,您无法在不详尽的情况下记住结果。要使memoization工作,您需要明确的子问题,而这里没有。