如何得到两个多重集的最小上界

时间:2013-07-17 01:22:13

标签: list prolog

我需要实现一个谓词:

leastUpper(L1,L2,L)
当L是多重L1和L2的最小上界时,将满足它。这意味着对于L中的每个元素X / N,X是出现在集合L1和L2中的至少一个中的原子,并且N是L1和L2中的X的最大索引。如果X没有出现在一个集合中,则该集合中的索引为0。

例如:

leastUpper([],[a/1,b/2,c/3],L) will be satisfied when L=[a/1,b/2,c/3]

or leastupper([a/2,b/3,c/2],[b/3,c/4,d/1],L) is satisfied if L=[a/2,b/3,c/4,d/1]. 

我当前的想法是这样的:对于L1中的每个元素X / N,检查L2中是否存在元素X / _。如果存在,则比较它们的索引以获得最大索引Nx,然后在L中添加X / Nx。同时,删除L1和L2中的相应元素。继续此过程直到L1结束。对于L1和L2中的其余元素,它们只出现在一组L1或L2中,只需将它们添加到L中。原始想法可以用以下谓词说明:

check(X/N,L2) :- member(X/_,L2),compare(...),append(X/Nx,L),delete(X/_,L1,L2).

我不知道我的想法是否正确以及如何在Prolog中实现它。欢迎任何想法,非常感谢!

2 个答案:

答案 0 :(得分:2)

我倾向于同意@mbratch。你跑过一个合乎逻辑的表达式来进入程序部分。我想出的答案要简单得多。关键是这句话:

  

对于L中的每个元素X / N,X是在L1和L2中的至少一个中出现的原子,并且N是L1和L2中X的最大索引。

您已在此处拥有逻辑定义。让我们简化它:最小上界的元素是集合L的元素X / N,使得N是集合中X / N的最大分母。这在Prolog中表达是微不足道的:

leastUpper(X/N, L) :-
    member(X/N, L),
    \+ (member(X/M, L), M > N).

如果X / N在L中并且没有L的成员X / M使得M大于N,则字面上说X / N是L的最小上限元素。

请注意两个" multisets"的最小上限。是两个列表的最小上限(列表和多集之间的唯一区别是顺序的概念,这里没有相关性),并且两个列表的最小上限与最小上限相同一个列表(两个列表连接)。惊喜! :)你的谓词现在有两行:

leastUpper(L1, L2, L) :-
    append(L1, L2, Concatenated),
    setof(X, leastUpper(X, Concatenated), L).

这符合您的要求:

?- leastUpper([a/2, b/3, c/2], [b/3, c/4, d/1], L).
L = [a/2, b/3, c/4, d/1].

学习如何以声明和逻辑方式思考到目前为止最难学习Prolog。

一些注意事项:

  • leastUpper/2是与leastUpper/3不同的谓词。值得注意的是,前者是发电机而后者不是发电机。重命名它可能是明智的。
  • leastUpper/2效率不高:这种遍历是O(N ^ 2)。您可以轻松地将其替换为排序,然后进行线性扫描,并实现O(N log N)。替换可能会长达5-6行,并且可能需要另一个辅助谓词,所以如果您关心这一点,请尝试自己实现它(这并不困难)。

答案 1 :(得分:0)

我自己的解决方案:

larger(X,Y,N):- X>=Y, N=X.
larger(X,Y,N):- X<Y,N=Y.

remove([],X,[]) :- !.
remove([X|T],X,L1) :- remove(T,X,L1), !.
remove([H|T],X,[H|L1]) :- remove(T,X,L1).

check(X/N) :- atom(X), integer(N), N > 0.

least_Upper([],M2,M2):-!.
least_Upper(M1,[],M1):-!.

least_Upper([X/N1|R1],L2,[X/N|R]):-      
                  maplist(check[X/N1|R1]),maplist(check,L2),member(X/N2,L2), 
          larger(N1,N2,N), remove(L2, X/N2, L2R), least_Upper(R1,L2R,R),!.

least_Upper([X/N1|R1],L2,[X/N|R]):- maplist(check,[X/N1|R1]),maplist(check,L2),
                  \+member(X/_,L2), N=N1, least_Upper(R1,L2,R),!.