我认为这是一个技术问题,我正在尝试编写一个程序,它会找到整数1,2,...,N的大小为K的所有子集。
在here我已经询问了我正在使用的子集功能。固定版本是:
subs(0,[],X).
subs(N,[A|R1],[A|R2]):-
N>0,
N1 is N-1,
subs(N1,R1,R2).
subs(N,[A|R1],[B|R2]):-
N>0,
subs(N,[A|R1],R2).
后来我编写了两个函数来帮助我找到集合中的最后一个元素以及除了最后一个元素之外的所有元素的子集(因为[A|Rest]
表示A
是第一个Rest
}是从2到最后,但我喜欢相反的 - 拥有最后一个元素和从第一个元素到最后一个元素的所有元素。功能是:
lastOf(A,[A]).
lastOf(A,[B|R]):-
lastOf(A,R).
subLast([],[X]).
subLast([A|R1],[A|R2]):-
subLast(R1,R2).
现在我写了一个函数,它创建了第一个N
自然数的列表:
setOf(0,[]).
setOf(N,Nums):-
lastOf(N,Nums),
N>0, N1 is N-1,
subLast(NeoNums,Nums),
setOf(N1, NeoNums).
结合以上所有内容我有:
choose(K,N,X):-
setOf(N,Y),
subs(K,X,Y).
运行它,例如在2
和4
,我得到:
?-choose(2,4,X).
X = [1, 2] ;
X = [1, 3] ;
X = [1, 4] ;
X = [2, 3] ;
X = [2, 4] ;
X = [3, 4] ;
abort
% Execution Aborted
14 ?- ERROR: Stream user_input:6:143 Syntax error: Unexpected end of clause
这些都是正确的输出,但问题是每次按下Enter键进行(可能的)下一个答案后,我会得到下一个,除了最后一个,我必须强制中止,因为它似乎程序陷入了某种无限循环。
有人可以帮忙吗?
我使用的是SWI-Prolog。
答案 0 :(得分:2)
如果您正在使用SWI-Prolog,还可以使用clpfd!这是choose/3
的{{3}}变体:
:- use_module(library(clpfd)).
choose(K,N,Zs) :-
length(Zs,K),
Zs ins 1..N,
chain(Zs,#<),
labeling([],Zs).
那就是它!以下是您在问题中提出的问题:
?- choose(2,4,Zs).
Zs = [1,2] ;
Zs = [1,3] ;
Zs = [1,4] ;
Zs = [2,3] ;
Zs = [2,4] ;
Zs = [3,4]. % the goal `choose(2,4,Zs)` terminates
答案 1 :(得分:1)
setOf
是问题所在。更具体地说 - lastOf
,它生成以N
结尾的无限数量的可能列表。无论如何,setOf可以更容易实现,并且更易读(并且终止):
setOf(0, []).
setOf(N, [N|T]) :-
N > 0,
N1 is N-1,
setOf(N1, T).
如果你不在乎数字的反向顺序,那就是这样。否则通过引入辅助谓词:
setOf(N, X) :- range(1, N, X).
% range(LowerBound, UpperBound, ResultList)
range(L, L, [L]).
range(L, U, [L|T]) :-
L < U,
L1 is L + 1,
range(L1, U, T).