【问题标题】:Prolog - Finding the longest increasing subsequenceProlog - 找到最长的增加子序列
【发布时间】:2026-01-04 15:30:02
【问题描述】:

我想在 Prolog 中解决以下练习:

对于整数列表Zsmax_sequence(Zs,Xs) 找到一个longest increasing subsequenceXs

示例查询:

?- max_sequence([1,2,1,2,3,4,2,1,2,1],Xs)。 Xs = [1,2,3,4]。 % 预期结果 ?- max_sequence([1,2,1,2,3,4,2,1,6,7,7,2,1,8],Xs)。 Xs = [1,2,3,4,6,7,8]。 % 预期结果

我不明白为什么...但是我的代码是错误的,结果总是false

max_sequence(L,R) :-
    cresc(L,[],R).

cresc([],[],[]).
cresc([H|T],C,[H|C]) :-
    maxList(H,C),
    \+ member(H,C),
    cresc(T,C,C).
cresc([H|T],C,C) :-
    member(H,C),
    cresc(T,C,C).       
cresc([H|T],C,C) :-
    \+ maxList(H,C),
    cresc(T,C,C).   

maxList(_,[]).
maxList(N, [H|T]) :-
    N>H,
    maxList(N,T).

我想知道我解决问题的方法是否正确。 感谢您的帮助!

【问题讨论】:

  • 您可以从 maxList/2 谓词之类的东西开始。从语义上讲,这是什么意思?它的目的是什么?如果N 大于L 的每个成员,或者L 无论如何都是空的,那么在我看来maxList(N, L) 会成功。这是你的意图吗?那么cresc/2 的第二个子句在C 未实例化时具有maxList(H, C)。这可能是不正确的,我敢打赌您可能会在 >/2 上看到一个实例化错误(尽管您没有确切说明您尝试过的示例或遇到的错误)。
  • maxList 是您编写的内容,检查 N 是否是已控制的那些(在 C 列表中)中的最大数字,即使 L 为空也会成功。是的,实例化错误是我最初的问题,但最重要的是,我的程序似乎无法按我的意愿运行,而且我不明白为什么(所以我的是语义问题)。
  • 我只有一个错误的序列而不是正确的序列([1,2,3,4])
  • 您应该编辑您的问题并显示更新后的代码并修复了实例化错误。
  • “序列”是指“子序列”,“最大”是指“最长”? (从你给出的例子中猜测)如果你给你的问题一个正确的名字,它可能会引起正确的注意。

标签: list prolog clpfd


【解决方案1】:

TL;DR:从高层次上解决问题:惯用思维;并且不要重新发明*:)


使用

:- use_module(library(clpfd)).

我们采取以下两个步骤:

  1. 我们首先使用 splitlistIfAdj/3(#>=)/3

    ?- splitlistIfAdj(#>=,[1,2,2,2,1,2,3,4,2,1,3,5,7,1],Zss).
    Zss = [[1,2],[2],[2],[1,2,3,4],[2],[1,3,5,7],[1]].
    
  2. 我们只对最大大小的子列表感兴趣。 max_of_by/3 可以排除所有其他的:

    ?- max_of_by(Xs,[[1,2],[2],[2],[1,2,3,4],[2],[1,3,5,7],[1]],length).
      Xs = [1,2,3,4]
    ; Xs = [1,3,5,7].
    

就是这样!我们把它放在一起定义list_longest_ascending_sublist/2

list_longest_ascending_sublist(Xs,Zs) :-
   splitlistAdjIf(#>=,Xs,Yss),
   max_of_by(Zs,Yss,length).

示例查询:

?- list_longest_ascending_sublist([1,2,2,2,1,2,3,4,2,1,3,5,7,1],Zs) . Zs = [1,2,3,4] ; Zs = [1,3,5,7]。 ?- list_longest_ascending_sublist([1,2,2,3,4,5,6,2,1,2,3,4,2,1,3,5,7,1],Zs )。 Zs = [2,3,4,5,6]。

【讨论】:

  • 非常感谢您的回答,但我的问题有点不同([1,2,2,2,1,2,3,4,2,1,3,5,7 ,1] 应该回答 [1,2,3,4,5,7])
【解决方案2】:

我完全看不懂你的方法,但是在swi-prolog 中使用Trace 命令,你可以一步一步地看到你的程序执行,看看它在哪里失败。试试看,你会发现你的代码出了什么问题。

无论如何,这可能是一个可能的解决方案:从列表的第一个元素开始,您应该简单地收集一个列表,直到元素增加,同时保持这个子列表的长度,这是第一个候选者。然后再次开始收集新列表及其长度,如果比候选者长,则切换它们,依此类推.. 在这里你可以找到代码:max_seqs,第一部分。

【讨论】: