通过回溯列表探索&相互递归

时间:2014-10-25 11:27:03

标签: prolog

我试图使用回溯来实现探索算法。目的是找到可能被称为“链条”的链条。使用两个规则的单词:

  • 如果选择X,那么X的所有其他实例也是如此
    • e.g。来自[a,b,b,a,b]我们需要[a,_,_,b,_]
  • 如果选择了Y,那么Y'反对' - 即距离末端等距离的那个。
    • e.g。使用[a,c,c,c,b]我们会[a,_,_,_,b]

所以abyxzbzxxcb将首先选择ab ... b ... cb。

    选择
  • a因为它是头
  • 按规则2选择最后一个
  • 按规则1,选择第一个b
  • 按规则2选择c
  • 由于没有其他c,代码应重新应用规则1以获得中间b,从中无法进一步移动。

我的想法是使用2个谓词的相互递归:

  • find_another:找到另一个具有相同字母的元素;
  • find_palindrome:从末尾选择等距离的元素。

我正在使用find_loop([a,b,y,x,z,b,z,x,x,c,b],Loop).对此进行测试,但未能获得中间(5,b),并且在第一个结果后停止。我认为在find_another中没有正确回溯以继续寻找更多b s,我担心即使这样做,我也会在途中丢失部分Hist(ory)。

或许更好的方法是在findall中使用find_another,然后将每个结果传递给find_palindrome,但我想我可以通过回溯来完成所有操作。

find_loop(Word, Loop) :-
    zip(Word, 0, WZ),
    length(Word, WL), Word_length is WL - 1,
    [X|_] = WZ,
    find_another(X, Word_length, WZ, [X], Loop).    
/*
Get a element with same letter
  if not in history, explore further via its palindrome
  else search for existing element's palindrome
*/
find_another((N,L), Word_length, Word, Hist_in, Hist_out) :-
    member((X,L), Word),
    (
    \+ member((X,L), Hist_in),
    find_another((N_palindrome,X), Word_length, Word, [(N_palindrome,X)| Hist_in], Hist_out)
    ;
    find_palindrome((N,L), Word_length, Word, Hist_in, Hist_out)
    ).

/*
Finds the palindrome element, and then looks for others with new letter
*/
find_palindrome((N,L), Word_length, Word, Hist_in, Hist_out) :-
    N_palindrome is Word_length - N,
    member((N_palindrome,X), Word),         
    (
        \+ member((N_palindrome,X), Hist_in) ->    
            Hist_next = [(N_palindrome,X)| Hist_in],
            find_another((N_palindrome,X), Word_length, Word, Hist_next, Hist_out)
        ;
            Hist_out = Hist_in
    ).

%% [a,b,c,...] becomes [(0,a),(1,b),...]
zip([], _, []).
zip([H | T], C, [(C,H)|Z] ) :-
    C1 is C + 1,
    zip(T,C1,Z).

1 个答案:

答案 0 :(得分:0)

好的,所以我仍然不太确定为什么相互递归不起作用,但我想我可以看到回溯应该删除历史的一部分(我实际上需要保留),所以回溯是错误的方式解决这个问题。考虑到这一点,我通过让find_another获得具有相同字母的所有其他元素然后递归列表来使概念更简单。这提供了正确的解决方案。希望我可以在这里概括我的学习,以避免再次出现这个错误! ; - )

find_another((_,L), Word_length, Word, Hist_in, Hist_out) :-
    findall((N1,L), member((N1,L), Word), Others),
    find_another_from_list(Others, Word_length, Word, Hist_in, Hist_out).

find_another_from_list([], _, _, Hist_out, Hist_out).
find_another_from_list([H|T], Word_length, Word, Hist_in, Hist_out) :-
    find_palindrome(H, Word_length, Word, Hist_in, Hist_tmp),
    find_another_from_list(T, Word_length, Word, Hist_tmp, Hist_out).