【问题标题】:Prolog Recursive Pancake SortingProlog 递归煎饼排序
【发布时间】:2021-03-24 16:07:17
【问题描述】:

我正在我的一个项目中工作,我想在 Prolog 中实现 pancake sorting,到目前为止,我已经完成了算法的大部分,但我需要创建将可能状态(排列)转换为的“函数”另一个。

initial_state([3,2,1]).
final_state([1,2,3]).

dfs(States):-
    initial_state(State),
    depth_first_search(State, [State], State).

depth_first_search(State,States,States):-
    final_state(State).

depth_first_search(State1,SoFarStates,States):-
    move(State1,State2),
    \+ member(State2,SoFarStates),
    append(SoFarStates,[State2],NewSoFarStates),
    depth_first_search(State2,NewSoFarStates,States).

所以我想在 move(State1,State2) 中使用一些递归,因此只要在“SoFarStates”中不存在特定排列(如果它执行计数器),则在一定次数的翻转后创建 State2( ?) 现在翻转第一个 n-1 并再次检查。

我是 prolog 的新手,我迷路了,这种实现背后的想法是什么?

【问题讨论】:

标签: list sorting recursion prolog logic


【解决方案1】:

这是我的方法:

1. pancake 谓词获取初始状态列表,并返回不同的翻转直到达到最终状态。

2.使用 splitSet 和 permute 谓词根据初始状态的长度生成翻转。

pancake([H|T],FlipState):-
    splitSet([H|T],_,Sublist),
    Sublist=[_|_], /* disallow empty list */
    permute(Sublist,N1),
    length([H|T],Len1),
    length(N1,Len2),
    Len1=Len2,
    FlipState=N1.

splitSet([ ],[ ],[ ]).
splitSet([H|T],[H|L],R) :-
    splitSet(T,L,R).
splitSet([H|T],L,[H|R]) :-
    splitSet(T,L,R).

permute([ ],[ ]) :- !.
permute(L,[X|R]) :-
    omit(X,L,M),
    permute(M,R).

omit(H,[H|T],T).
omit(X,[H|L],[H|R]) :-
    omit(X,L,R).

示例:-

?-pancake([3,2,1],P)
P = [3, 2, 1]
P = [3, 1, 2]
P = [2, 3, 1]
P = [2, 1, 3]
P = [1, 3, 2]
P = [1, 2, 3]

?-pancake([322,6],P)
P = [322, 6]
P = [6, 322]
false

【讨论】:

  • 你的评论给了我一些关于我的问题的想法,但是在 3 个元素的列表中可能发生的翻转(对于 [3,2,1])是(翻转)[2,3,1 ] 和 [1,2,3] 你可以翻转前 2(3,2 到 2,3)或“第一个”3。所以我相信我不应该有其余的排列。我的 soFarStates 例如可以是 [3,2,1] -> [2,3,1] -> [1,3,2] -> [3,1,2] -> [2,1,3] -> [1,2,3]。
【解决方案2】:
maximum([A],A,N,N,A).
maximum([H|T],A,N,Posneu,Last):-
    NN is N+1,
    maximum(T,B,NN,Pos,Last),
    (   H>B
    ->  A=H,
        Posneu = N
    ;   A=B,
        Posneu = Pos).

pancakesort([], []).
pancakesort(L, Lsort):-
    maximum(L,Max,1,PosMax,Last),
    (   Last == Max
    ->  append(Lwo,[Max],L)
    ;   length(Ltmp,PosMax),
        append(Ltmp,Ltmp1,L),
        reverse(Ltmp,Pmtl),
        append(Pmtl,Ltmp1,[Max|Owl]),
        reverse(Owl,Lwo)
    ),
    pancakesort(Lwo,LwoSort),
    append(LwoSort,[Max],Lsort).
    
?- pancakesort([1,4,2,6],L).
L = [1, 2, 4, 6] ;
false.

所以每个迭代/递归步骤的想法是找到最大值,翻转包含最大值的堆作为最后一个元素,以便最大的煎饼在顶部,然后再次翻转它,使最大的煎饼在底部。重复煎饼堆,没有最下面的煎饼。

所以对于我的实现,我需要一个辅助谓词maximum/5,它在列表中搜索最大值并返回最大值的位置。为了让它更有效率,它还返回最后一个元素,以便程序首先检查最大的煎饼是否已经在底部(Last == Max)。如果不是这种情况,则第一个 PosMax 煎饼 (Ltmp) 将从堆中分离出来,翻转 (reverse(Ltmp,Pmtl)) 并放回堆中。现在最大的煎饼位于顶部([Max|Owl]),因此必须翻转整个堆(reverse(Owl,Lwo))。由于最大的煎饼将被移除,因此在翻转之前更容易将其移除。现在对未排序的堆重复该过程以获得排序的子堆。在末尾附加最大元素,您将得到一个排序列表。如果剩下的堆上没有煎饼,则对堆进行排序(pancakesort([], []).

如果最大的煎饼已经在底部,则更紧凑但效率更低的实现将忽略该案例的测试:

maximum([A],A,N,N).
maximum([H|T],A,N,Posneu):-
    NN is N+1,
    maximum(T,B,NN,Pos),
    (   H>B
    ->  A=H,
        Posneu = N
    ;   A=B,
        Posneu = Pos).

pancakesort([], []).
pancakesort(L, Lsort):-
    maximum(L,Max,1,PosMax),
    length(Ltmp,PosMax),
    append(Ltmp,Ltmp1,L),
    reverse(Ltmp,Pmtl),
    append(Pmtl,Ltmp1,[Max|Owl]),
    reverse(Owl,Lwo),
    pancakesort(Lwo,LwoSort),
    append(LwoSort,[Max],Lsort).

【讨论】:

    【解决方案3】:

    您的答案不正确,但它们对于深入了解我真正想要的东西至关重要。这是move的实现。

    move(State1, State2) :-
        length(State1, N1),              /* Number of pancakes plus the plate */
        N is N1 - 1,                                    /* Number of pancakes */
        between(1, N, Operator),               /* Select a pancake to reverse
                                                     the whole stack above it */
        State1 \= [Operator|_],         /* This should not be the top pancake */
        append(Prefix, [Operator|Rest], State1),    /* Isolate pancakes above
                                                   the one acting as operator */
        reverse(Prefix, RevPrefix),                           /* Reverse them */
        append([Operator|RevPrefix], Rest, State2).  /* Build the final stack */
    

    【讨论】:

      猜你喜欢
      • 2018-06-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-26
      • 2011-12-09
      • 2014-06-16
      相关资源
      最近更新 更多