我对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中的第一个选项?提前谢谢。
答案 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] ;
...