Prolog:查找长度>=3的子列表

4
我希望能够创建一个谓词,用于检查一个列表是否可以被分成至少包含三个元素的子列表。
例如:
findgroups([1,2,3,4,5,6,7,8,9],L1).

具有以下解决方案:

L1=[[1,2,3],[4,5,6],[7,8,9]]
L1=[[1,2,3,4],[5,6,7,8,9]]
L1=[[1,2,3,4,5],[6,7,8,9]]
L1=[[1,2,3,4,5,6],[7,8,9]]

然而,以下内容将会失败:

findgroups([1,2,3,4,5]).

我已经基于使用append将列表分成两个子项编写了一些谓词,但是我对处理多个子列表感到困惑。

非常感谢您的帮助

祝好 J

2个回答

4
让我们从一个好的名称开始!findgroups/2表示您希望命令Prolog:Prolog,请为我找一些组!快点!这真的合适吗?让我们看看:
?- findgroups(L, [[1,2,3],[4,5,6],[7,8,9]]).

谁在这里寻找任何组?他们已经存在!所以你的名字真的是个错误的称呼。相反,通过描述每个参数来组成一个名称。第一个参数是关于列表的,第二个参数是关于列表的列表。因此:

?- list_lists(L, [[1,2,3],[4,5,6],[7,8,9]]).

更好了,但有点太笼统。也许应该是:
?- elements_trigroups(L, [[1,2,3],[4,5,6],[7,8,9]]).

现在查询的问题是:这里有所有的三元组,对应的元素是什么?“Elements”这个词太长了,用“els”也很好。
es_trigroups(Es, Ess) :-
   phrase(seqq(Ess), Es).

请注意变量名称:Es:一个E的列表。而Ess是一个E的列表,这个列表又是E的列表。

使用在另一个答案中定义的seqq//1

该死,它仍然成功地执行了:

?- es_trigroups([1,2,3,4,5], [Es,Fs]).
   Es = [], Fs = [1,2,3,4,5]
;  Es = [1], Fs = [2,3,4,5]
;  ... .

但这并不是很糟糕,因为它能够满足您所需的所有情况。简而言之:这种关系太笼统了,我们需要将其专业化。
专业化关系的简单方法是添加进一步的目标,例如:
es_trigroups(Es, Ess) :-
   trigroups(Ess),
   phrase(seqq(Ess), Es).

trigroups([]).
trigroups([Es|Ess]) :-
   Es = [_,_,_|_],
   trigroups(Ess).

现在一切似乎都很好。只有一件事情不太好:终止属性可以更好。有时我们需要交换目标。

es_trigroups_bis(Es, Ess) :-
   phrase(seqq(Ess), Es),
   trigroups(Ess).

得出的终止条件如下:

es_trigroups(A,B)在b(B)的情况下终止。
    % 最优。 找到循环:[es_trigroups(_,[[_,_,_|_]|_]),es_trigroups(y,[[_,_,_|_]|_])]. NTI花费了0ms,74i,74i
es_trigroups_bis(A,B)在b(B)的情况下终止。
    % 最优。 找到循环:[es_trigroups_bis(_,[[]|_]),es_trigroups_bis(y,[[]|_])]. NTI花费了0ms,79i,79i

但是实际上我们想要的是,终止条件不仅取决于B(第二个参数),还取决于单独的A。也就是说,要么A要么B可以保证终止。为此,我们必须交错两个定义:

es_trigroups_ter(Es, Ess) :-
   phrase(seq3s(Ess), Es).

seq3s([]) --> [].
seq3s([Es|Ess]) --> {Es = [_,_,_|_]}, seq(Es), seq3s(Ess).

现在,终止条件优秀

es_trigroups_ter(A,B) 如果 b(A);b(B) 终止。
    % 最优。循环已找到:[es_trigroups_ter([A|_],[[A,_,_|_]|_])]. NTI 花费 0 毫秒,77i,77i

0

也许这个非常简单的解决方案可以做到

findgroups([], []).
findgroups(L, [[A,B,C|D]|Gs]) :-
    append([A,B,C|D], R, L),
    findgroups(R, Gs).

最后一个解决方案虽然不是必需的,但它是正确的,因为您不能排除仅包含1个元素的组。

?- findgroups([1,2,3,4,5,6,7,8,9], Gs).
Gs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] ;
Gs = [[1, 2, 3], [4, 5, 6, 7, 8, 9]] ;
Gs = [[1, 2, 3, 4], [5, 6, 7, 8, 9]] ;
Gs = [[1, 2, 3, 4, 5], [6, 7, 8, 9]] ;
Gs = [[1, 2, 3, 4, 5, 6], [7, 8, 9]] ;
Gs = [[1, 2, 3, 4, 5, 6, 7, 8|...]] ;
false.

为了完全匹配示例,我会这样写

findgroups(L, Gs) :- findgroups_(L, Gs), Gs = [_,_|_].
findgroups_([], []).
findgroups_(L, [[A,B,C|D]|Gs]) :-
    append([A,B,C|D], R, L),
    findgroups_(R, Gs).

感谢你们两位的出色回答,让我学到了很多。我目前正在尝试添加额外的目标来进一步限制分组。 - John

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接