【问题标题】:Prolog delete all increasing subseries from a listProlog 从列表中删除所有增加的子系列
【发布时间】:2021-01-13 14:02:27
【问题描述】:

任务是从列表中删除所有增加的子系列。例如: deleteInc([2,4,6,5,8,12,8,3],L) 应该产生 L=[8,3] 作为结果

我试图解决它,但它无法正常工作,我无法找出正确的解决方案。有人可以帮我一个正确的解决方案吗?在此先感谢:)

我的代码:

deleteInc([],[]).
deleteInc([H1,H2|T],L):-
    H2>=H1,
    !,
    deleteInc(T,L).
deleteInc([H1,H2|T],[H2|T2]):-
    H2<H1,
    deleteInc(T,T2).

【问题讨论】:

  • 你能解释一下吗,子系列是什么意思?你期待什么样的输出?
  • 对于给定的输入,第一个增加的子序列是 2,4,6,然后是 5,8,12,这也是一个增加的子序列,然后是 8,3 数字不增加所以结果是 8,3。
  • 一次检查 3 个值吗? [2,4,6],然后 [5,8,12] ...

标签: list prolog series


【解决方案1】:

这就是我所做的,假设它一次检查三个值:

deleteInc([],[]).
deleteInc([H1,H2,_H3|T],L):-
    H2>=H1,
    !,
    deleteInc(T,L).
deleteInc([H1,H2|T],[H1,H2|T2]):-
    H2<H1,!,
    deleteInc(T,T2).

示例:

?-deleteInc([2,4,6,5,8,12,8,3],L).
L = [8, 3]

?-deleteInc([2,4,6,5,8,12,15,21,25,7,3],L).
L = [7, 3]

?-deleteInc([2,4,6,5,8,12,15,21,25,55,77,88,65,38],L).
L = [65, 38]

这是一种收集所有不增加的组合的方法:

deleteInc(L,[],L).
deleteInc([H1,H2|T],L,Rest):-
    H2>=H1,
    !,
    deleteInc(T,L,Rest).
deleteInc([H1,H2|T],[H1,H2|L],Rest):-
    H2<H1,!,
    deleteInc(T,L,Rest).

示例:-

?-deleteInc([2,4,6,5,8,12,15,21,25,55,77,88,65,38],L,_).
L = []
L = []
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5, 65, 38]

?-deleteInc([2,4,6,5,8,12,15,21,25,7,3],L,_).
L = []
L = []
L = [6, 5]
L = [6, 5]
L = [6, 5]
L = [6, 5, 25, 7]

?-deleteInc([2,4,6,5,8,12,8,3],L,_).
L = []
L = []
L = [6, 5]
L = [6, 5]
L = [6, 5, 8, 3]

【讨论】:

    【解决方案2】:

    我会这样实现它:

    deleteInc(In, Out):-
        deleteInc(In,Out,new).
    
    deleteInc([A],[A],new).
    deleteInc([_],[],incr).
    deleteInc([H1,H2|T],L,_):-
        H2>=H1,
        !,
        deleteInc([H2|T],L,incr).
    deleteInc([H1,H2|T],T2,incr):-
        H2<H1,
        deleteInc([H2|T],T2,new).
    deleteInc([H1,H2|T],[H1|T2],new):-
        H2<H1,
        deleteInc([H2|T],T2,new).
    

    第三个属性表明您当前是处于new 还是increasing 连续。

    如果列表的两个头元素按升序排列,则第三个元素几乎被忽略。请注意转发的不是列表T,而是[H2|T],因为您需要元素H2 进行进一步比较。如果你处于连续 (incr) 并且当前两个头部元素没有增加,你和以前一样:忽略。但是,如果您刚刚开始 new 连续并且当前的头元素正在减少,则将第一个头元素放在返回列表中。一个元素的特殊情况。让我们检查一下:

    ?- deleteInc([2,4,6,5,8,12,8,3],L).
    L = [8, 3] ;
    false.
    

    看起来不错。

    【讨论】:

      【解决方案3】:

      如果中间的元素小于第一个但大于第三个,则另一种方法是只检查 3 个后续元素。如果是这种情况:存储元素。如果不是这种情况:检查没有第一个 head 元素的列表。

      为剩下的 2 个元素添加规则。还需要对第一个元素进行特殊处理,因为这不在主要规则中。通过使用 cut,您可以在最后一行“捕捉”剩余的大小写(两个增加的元素或带有一个或没有元素的奇怪输入)。请注意,规则的顺序对于程序的运行很重要。

      deleteInc([H1,H2|L], [H1|R]):-
          H1 >= H2,
          !,
          deleteInc1([H1,H2|L], R).
      deleteInc([H1,H2|L], R):-
          deleteInc1([H1,H2|L], R).
      
      deleteInc1([H1,H2,H3|L], [H2|R]):-
          H1 > H2,
          H2 > H3,
          !,
          deleteInc1([H2,H3|L], R).
      deleteInc1([A,B],[B]):-
          A > B,
          !.
      deleteInc1([_|L], R):-
          !,
          deleteInc1(L, R).
      deleteInc1(_,[]).
      

      让我们测试一下:

      ?- deleteInc([2,4,6,5,8,12,8,3],L).
      L = [8, 3].
      

      有效(用于数字列表)。

      【讨论】:

        【解决方案4】:

        另一种解决方案是计算条纹的长度并过滤掉所有包含多个元素的结果。以下代码从第一个元素的计数 0 开始,并使用后继谓词 s/1 进行计数:

        deleteInc(In, Out):-
            countInc(In,0,InC),
            delInc(InC,Out).
        
        countInc([A], C, [(A,C)]).
        countInc([A,B|L], C, Out):-
            A =< B,
            countInc([B|L], s(C), Out).
        countInc([A,B|L], C, [(A,C)|Out]):-
            A > B,
            countInc([B|L], 0, Out).
            
        delInc([],[]).
        delInc([(E,0)|L],[E|R]):-
            delInc(L,R).
        delInc([(_,s(_))|L],R):-
            delInc(L,R).
        

        输出:

        ?- deleteInc([2,4,6,5,8,12,8,3],L)
        L = [8, 3] ;
        false.
        

        如预期的那样

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多