Prolog - 子集

时间:2014-11-22 22:25:52

标签: prolog

我对Prolog有点新意。我试图编写一个函数子集(Set,Subset)来确定Subset是否是Set(duh)的子集。此外,如果第二个参数未实例化,则应输出每个可能的子集。现在,它在两个参数都被实例化时都有效,但是当我试图输出所有子集时,它会遇到member / 2的问题。例如:

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

这是我的代码:

% subset/2
% subset(Set, Subset) iff Subset is a subset of Set
subset(_, []).
subset(Set, [H|T]) :-
  member(H, Set),
  subset(Set, T).

基本上,如何让成员不继续选择Set中的第一个选项?提前谢谢。

3 个答案:

答案 0 :(得分:3)

(包括SICStus和SWI在内的许多Prolog系统在其库中都有subset/2,而是subset(Subset, Set);它也不是一个干净的关系......)

这完全取决于你的意思。 [1, 1]是有效集吗?他们必须按一个顺序发生吗?如果您允许重复,您的定义很好。毕竟你的定义是:

  

set_subset(Set, Subset)Subset的所有元素都是Set

的元素

您感到惊讶的是,您现在拥有无限的解决方案。而且,更糟糕的是,该集以非常不公平的方式列举。如果您担心的只是精确的订单解决方案,请考虑:

?- length(Subset,N), set_subset([1,2,3], Subset).
Subset = [], N = 0 ;
Subset = [1], N = 1 ;
Subset = [2], N = 1 ;
Subset = [3], N = 1 ;
Subset = [1, 1], N = 2 ;
Subset = [1, 2], N = 2 ;
Subset = [1, 3], N = 2 ;
Subset = [2, 1], N = 2 ;
Subset = [2, 2], N = 2 ;
Subset = [2, 3], N = 2 ...

如果你希望Subset有很多解决方案,你可能想要一个子序列。请参阅this answer

答案 1 :(得分:2)

为了枚举子集,我不认为有必要生成排列,毕竟一组不应该关心排序。所以典型的text book解决方案是:

% subset(-Set, +Set)
subset([X|L], [X|R]) :-
   subset(L, R).
subset(L, [_|R]) :-
   subset(L, R).
subset([], []).

将此与其他解决方案进行比较:

此解决方案:

?- subset(X, [1,2,3]), write(X), nl, fail; true.
[1,2,3]
[1,2]
[1,3]
[1]
[2,3]
[2]
[3]
[]

其他capellis解决方案:

?- subset([1,2,3], X), write(X), nl, fail; true.
[]
[1]
[1,2]
[1,2,3]
[1,3]
[1,3,2]
[2]
[2,1]
[2,1,3]
[2,3]
[2,3,1]
[3]
[3,1]
[3,1,2]
[3,2]
[3,2,1]

从集合论我们知道| P(A)| = 2 ^ | A |,因此对于3个元素,长输入子集应该生成8个子集。这就是该解决方案的作用,但其他解决方案枚举了许多冗余子集的方法。

答案 2 :(得分:1)

而不是member / 2,请尝试选择/ 3

subset(_, []).
subset(Set, [H|T]) :-
  select(H, Set, Rest),
  subset(Rest, T).

所以你得到

?- subset([a,b,c],X).
X = [] ;
X = [a] ;
X = [a, b] ;
X = [a, b, c] ;
X = [a, c] ;
...