我是Prolog的初学者,这是我的问题:
我有一个没有重复的整数排序列表,即[1,2,3,11,12,13,14,21,22,23,24,25]
我想写一个谓词,找到列表元素中最长的连续子列表,即最长列表,其中每个整数后跟整数(在自然数集中)。
在上面的示例中,此列表为[21,22,23,24,25]
,其中length = 5
。
如果有多个列表具有相同的最大长度,我只对其中一个感兴趣,无论哪个。
它应该像这样工作:
maxCont([1,2,3,11,12,13,14,21,22,23,24,25],Lst]).
Lst = [21,22,23,24,25].
答案 0 :(得分:2)
首先,我们根据clpfd和bool01_t/2
定义z_nonsucc_t/3
:
:- use_module(library(clpfd)). z_nonsucc_t(X,Y,T) :- Y #\= X+1 #<==> B, bool01_t(B,T).
要将整数列表拆分为连续的runs,我们使用splitlistIfAdj/3
,如下所示:
?- splitlistIfAdj(z_nonsucc_t,[1,2,3,11,12,13,14,21,22,23,24,25],Pss).
Pss = [[1,2,3],[11,12,13,14],[21,22,23,24,25]].
接下来,我们根据meta-predicate,if_/3
和(#>)/3
定义(#>=)/3
max_of_by/3
:
max_of_by(X,[E|Es],P_2) :-
call(P_2,E,V),
max_of_by_aux(Es,P_2,V,[E],Rs),
reverse(Rs,Xs),
member(X,Xs).
max_of_by_aux([] , _ ,_ ,Bs ,Bs).
max_of_by_aux([E|Es],P_2,V0,Bs0,Bs) :-
call(P_2,E,V),
if_(V #> V0, Bs1=[], Bs1=Bs0),
if_(V #>= V0, (V1 = V , Bs2 = [E|Bs1]),
(V1 = V0, Bs2 = Bs1 )),
max_of_by_aux(Es,P_2,V1,Bs2,Bs).
要获得最长的列表,我们将meta-predicate max_of_by/3
与length/2
一起使用,如下所示:
?- max_of_by(Xs,[[1,2,3],[11,12,13,14],[21,22,23,24,25]],length).
Xs = [21,22,23,24,25].
请注意max_of_by/3
在绑定案例中可能会多次成功:
?- max_of_by(Xs,[[1,2,3],[11,12,13,14,15],[21,22,23,24,25]],length). Xs = [11,12,13,14,15] ; Xs = [21,22,23,24,25].
将所有内容放在谓词maxCont/2
中:
maxCont(Zs,Xs) :-
splitlistIfAdj(z_nonsucc_t,Zs,Pss),
max_of_by(Xs,Pss,length).
示例查询:
?- maxCont([1,2,3,11,12,13,14, 21,22,23,24,25],Xs).
Xs = [21,22,23,24,25].
?- maxCont([1,2,3,11,12,13,14,15,21,22,23,24,25],Xs).
Xs = [11,12,13,14,15]
; Xs = [21,22,23,24,25].
答案 1 :(得分:-1)
对于那里的任何其他学生,这里是一个回溯版本,我将在内容解释:
% start clause
lsl([X|Xs], R) :-
% call the work clause starting with contiguous runs of length 1.
lsl(Xs, 1-[X], 0-[], S),
% for every equal-maximum run, backtrack to bind solutions to R.
member(R, S).
% Three base cases when no more items to process:
% Case 1: current run length L exceeds length of all others, M.
lsl([], L-R, M-_, [R]) :- L > M, !.
% Case 2: current run length L is equal to length of all others, M.
lsl([], L-R, M-Acc, S) :- L == M, !, append(Acc, [R], S).
% Case 3: current run length L is too short, just use accumulated solutions S.
lsl([], _, _-S, S).
% main work clause
lsl([X|Xs], L-R, M-Acc, S) :-
% retrieve the last item Y in the current run
last(R, Y),
% check to see if the next item is an immediate successor
X is Y + 1,
% it is a successor, so cut to prevent subsequent clauses from being run
!,
% compute the new run length to include X
NewL is L + 1,
% append X to the end of the current run
append(R, [X], NewR),
% continue processing Xs with the new run
lsl(Xs, NewL-NewR, M-Acc, S).
% Three cases for what to do when the current run has ended:
% Case 1: current run length L exceeds length of all others, M.
lsl([X|Xs], L-R, M-_, S) :- L > M, !, lsl(Xs, 1-[X], L-[R], S).
% Case 2: current run length L is equal to length of all others, M.
lsl([X|Xs], L-R, M-Acc, S) :- L == M, !, lsl(Xs, 1-[X], L-[R|Acc], S).
% Case 3: current run length L is too short, reject current run and continue.
lsl([X|Xs], _, M-Acc, S) :- lsl(Xs, 1-[X], M-Acc, S).