在Prolog中找到最长的连续子列表

时间:2014-10-12 20:41:37

标签: list prolog

我是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].

2 个答案:

答案 0 :(得分:2)

首先,我们根据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]].

接下来,我们根据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).

要获得最长的列表,我们将 max_of_by/3length/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).