[英]Prolog Recursive Pancake Sorting
我正在我的一个项目中工作,我想在 Prolog 中实现煎饼排序,到目前为止,我已经完成了算法的大部分内容,但我需要创建将可能的 state(排列)转换为另一个的“函数”。
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 的新手,我迷路了,这种实现背后的想法是什么?
这是我的方法:
1. pancake 谓词获取最初的 state 列表,并返回不同的翻转,直到达到最终的 state。
2.使用 splitSet 和 permute 谓词根据初始 state 的长度生成翻转。
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
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
,它在列表中搜索最大值并返回最大值的 position。 为了让它更有效率,它还返回最后一个元素,以便程序首先检查最大的煎饼是否已经在底部( Last == Max
)。 如果不是这种情况,则将第一个PosMax
煎饼 ( Ltmp
) 从堆中分离出来,翻转 ( reverse(Ltmp,Pmtl)
) 并放回堆上。 现在最大的煎饼位于顶部( [Max|Owl]
),因此必须翻转整个堆( reverse(Owl,Lwo)
)。 由于最大的煎饼将被移除,因此在翻转之前更容易将其移除。 现在对未排序的堆重复该过程以获得排序的子堆。 Append 最后的最大元素,你得到一个排序列表。 如果剩下的堆上没有煎饼,则对堆进行排序( 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).
你的答案不正确,但它们对于深入了解我真正想要的东西至关重要。 这是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 */
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.