Longest increasing subset Prolog

前端 未结 2 1323
被撕碎了的回忆
被撕碎了的回忆 2021-01-24 03:40

I want to create in Prolog to find longest increasing subset of entered list. For example, you enter list of [3,1,2] and the output is [1,2],

?- subset([3,1,2],          


        
相关标签:
2条回答
  • 2021-01-24 04:06

    Just out of curiosity, would it be possible in prolog to realize something like this for finding longest increasing subsequence:

    • You find all subsets of list
    • Than you find, which of these subsets are increasing
    • And then you search for the longest

    If it's possible, how could I do that in Prolog?

    0 讨论(0)
  • 2021-01-24 04:18

    Do you mean [1,3,5,6,7] to be the answer for [4,1,3,8,9,5,6,7]? IOW, do you really mean subsets, or just sublists, i.e. contiguous portions of the list?

    If the latter is the case, you won't need subsets. The search is linear. If in a list [a,b,c,d,e,f] you find that d > e and the increasing sequence [a,b,c,d] stops, you don't need to restart the search from b now: the sequence will still break at d. You will just continue your search from e.

    So, we'll just carry around some additional information during the search, viz. the current and the winning-so-far sub-sequences. And their lengths.

    longest_incr([],0-[]).
    longest_incr([A|B],RL-R):-                  % R is the result, of length RL
        longest_aux(B,[],0, [A],1, RL-R). 
    
    longest_aux([],   Win,N, Curr,K, RL-R):- 
        ( K>N -> RL=K, reverse(Curr,R) ; RL=N, reverse(Win,R) ).
    longest_aux([A|B],Win,N, Curr,K, RL-R):- Curr = [X|_], L is K,
        ( A>X -> longest_aux(B,Win, N, [A|Curr],L+1,RL-R)    % keep adding
        ; L>N -> longest_aux(B,Curr,K, [A],     1,  RL-R)    % switch the winner
        ;        longest_aux(B,Win, N, [A],     1,  RL-R)    % winner unbeaten 
        ).
    

    If OTOH you really need the longest subset ... there's a contradiction there. A set can have its elements rearranged, so the longest subset of a given list will be

    longset_subset(L,R):- sort(L,S), R=S.
    

    Perhaps you mean the longest order-preserving sub-sequence, i.e. it is allowed to be non-contiguous. Then you can gather all solutions to your subset with findall or similar predicate, and analyze these results:

    longest_subseq(L,R):- 
        findall( S, subset(L,S), X),
        maplist( longest_incr, X, Y),
        keysort( Y, Z), 
        last( Z, _Len-R).
    

    The above has a lot of redundancy in it. We can attempt to improve its efficiency by only allowing the increasing subsequences:

    incr_subseq([],[]).
    incr_subseq([_|X],Y):- incr_subseq(X,Y).
    incr_subseq([A|X],[A|Y]):- incr_subseq(X,Y), ( Y=[] ; Y=[B|_], A<B).
    

    Now all the sub-sequences found by the above predicate will be increasing, so we can just take their lengths:

    lenlist(List,Len-List) :- length(List,Len).
    longest_subseq(L,R):- 
        findall( S, incr_subseq(L,S), X),
        maplist( lenlist, X, Y),
        keysort( Y, Z), 
        last( Z, _Len-R).
    

    Or, the linear searching longest_incr could be tweaked for a more efficient solution. Instead of maintaining just one winning sub-sequence, it would maintain all the relevant possibilities as it goes along the input list.

    0 讨论(0)
提交回复
热议问题