2013-03-27 78 views
1

我想在Prolog中創建查找輸入列表中最長的子集。例如,您輸入的[3,1,2]列表,輸出爲[1,2],增長最長的子集Prolog

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

我有代碼顯示了這個列表的所有子集:

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

任何人都可以幫助我找到最長的增長子集?

回答

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可以調整爲更有效的解決方案。它不會只維護一個獲勝的子序列,而是會沿着輸入列表保留所有相關的可能性。

+0

我實際上假設他的意思是「最長的子序列」,基於他的「子集」。有很多這樣做的算法。在他的情況下,他可以簡單列舉所有增加的子序列(他稱之爲子集)並查看哪一個最長。 – 2013-03-27 11:16:14

+0

@Boris你的意思是連續的,還是非連續的?基於他的「子集」,或許是第二種情況? – 2013-03-27 11:28:49

+0

http://en.wikipedia.org/wiki/Longest_increasing_subsequence非連續的,每個定義。如果它是連續的,我會猜測它將被稱爲子串。然而順序很重要(因此順序)。有大量可用的算法。 – 2013-03-27 11:30:58

0

只是出於好奇,那會是在序言中可以實現這樣的尋找最長遞增子:

  • 您發現列表
  • 的所有子集比你會發現,這些子集是increasing
  • 然後你搜索最長

如果有可能,我怎麼能做到這一點的Prolog的?

+0

的列表'X',答案'R'將滿足'sort(X,R)'。因爲集合被認爲是平等的,不管它們的元素的順序是什麼。如果你的意思是*子序列*,即包含原始順序的元素和可能來自列表的非連續區域的元素,那麼這就是這個問題所要求的。 – 2013-04-06 11:46:23

+0

我已經更新了我的答案。我調整了你的想法順便說一句 - 我測試的子序列的增加,因爲它們正在生成。 – 2013-04-07 16:34:21