增长最快的子集Prolog

时间:2013-03-27 09:11:20

标签: prolog

我想在Prolog中创建以找到输入列表中增长最长的子集。例如,输入[3,1,2]列表,输出为[1,2],

?- subset([3,1,2], X).
X = [1,2]

我的代码显示了此列表的所有子集:

subset([],[]).
subset([_|X],Y):-subset(X,Y).
subset([A|X],[A|Y]):-subset(X,Y).

任何人都可以帮我找到增长最快的子集吗?

2 个答案:

答案 0 :(得分:1)

您的意思是[1,3,5,6,7][4,1,3,8,9,5,6,7]的答案吗? IOW,你真的是指子集,还是只是子列表,即列表中的连续部分?

如果是后者,则不需要子集。搜索是线性的。如果在列表[a,b,c,d,e,f]中您发现d > e且增加的序列[a,b,c,d]停止,则您无需立即从b重新开始搜索:序列仍将中断在d。您只需从e继续搜索。

因此,我们只会在搜索过程中携带一些额外的信息,即。当前和获胜的子序列。他们的长度。

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 
    ).

如果OTOH你真的需要最长的子集......那里就有矛盾了。集合可以重新排列其元素,因此给定列表的最长子集将是

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

也许您的意思是最长的保留顺序的子序列,即允许它是非连续的。然后,您可以使用subset或类似谓词收集findall的所有解法,并分析这些结果:

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

上面有很多冗余。我们可以通过仅允许增加子序列来尝试提高效率:

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).

现在上述谓词找到的所有子序列都会增加,所以我们可以把他们的length s:

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).

或者,可以调整线性搜索longest_incr以获得更有效的解决方案。它不是只保留一个获胜的子序列,而是在输入列表中保持所有相关的可能性。

答案 1 :(得分:0)

出于好奇,在prolog中有可能实现这样的事情来寻找最长的后续序列:

  • 您可以找到列表的所有子集
  • 比你发现,这些子集中的哪一个正在增加
  • 然后你搜索最长的

如果有可能,我怎么能在Prolog中做到这一点?