根据属性生成N的所有排列(N-给定):每2 <= i <= n存在1 <= j <= i, 因此| v(i)-v(j)| = 1。我找到了一个解决方案,它建立了前N个数字的列表(将其反向生成),将其反转,测试是否满足条件,然后将每个数字应用于使用候选谓词找到的可能排列。这是到目前为止可以使用的代码:
% candidate returns each number from the list and the list without it
% candidate(L - list, R - integer, L1 - list)
% flow(i,o,o)
% candidate(l1...ln)= - l1,l2...ln
% - (e,l1 U L), (e,L) = candidate(l2...ln)
candidate([H|T],H,T).
candidate([H|T],R,[H|T1]):-candidate(T,R,T1).
%build(N - integer, L - list)
%flow(i,o)
%build(l1...ln,n) = - [], n = 0 or 1
% - build(l2...ln,n-1), n>1
build(0,[]).
build(1,[]).
build(N1,[N|L]) :- N1 > 1, N is N1 - 1, build(N,L).
%reverse(L - input list, Z - list, R - list)
%flow(i,o,i)
%reverse(l1...ln) = - [], list is empty
% - l1 U reverse(l2...ln)
reverse([],Z,Z).
reverse([H|T],Z,Acc) :- reverse(T,Z,[H|Acc]).
%buildReverse(N - integer, R - list)
%flow(i,o)
buildReverse(N1,R):-build(N1+1,R1),reverse(R1,R,[]).
%checks whether the condition in the requirement
%nrTest(L - list, R - int, I - int)
%nrTest(i,i,o)
%nrTest(l1...ln,r,i) = - false, l1 = r, i = 1
% - true, abs(l1-r)= 1, list length is 1
% - true, abs(l1-r)= 1
% - nrTest(l2...ln,r,1)
% - nrTest(l2...ln,r,1), i = 0, l1 = r
nrTest([],0,_).
nrTest([R|T],R,0):-nrTest(T,R,1).
nrTest([R|_T],R,1):-!,fail.
nrTest([H],R,_):-1 is abs(H-R),true,!.
nrTest([H|_T],R,_):-1 is abs(H-R),true,!.
nrTest([_H|T],R,_I):-nrTest(T,R,1).
% checks if for every element of the list the condition in the
% requirement is met
% test2(L - list, R - list)
% flow(i,i)
% test2(l1...ln,r1...rn) = - false, lists are empty
% - true, first list is empty
% - true, lists have one element each
% - test2(l2...ln,r1...rn), if
% nrTest(r1...rn,l1,0)
test2([],[]):-false.
test2([],_):-true.
test2([_],[_]):-true.
test2([H|T],R):-nrTest(R,H,0),test2(T,R),!.
%wrapper for test2
%test2Wrap(R - list)
%flow(i)
test2Wrap([]):-false.
test2Wrap([_]):-true.
test2Wrap(R):-test2(R,R).
%perm2(L - list, R - list)
%flow(i,o)
%perm2(l1...ln,r1...rn) = - [], list is empty
% - perm2(candidate(l1...ln,r1),r2...rn),
% otherwise
perm2([],[]).
perm2(L,[E|T]):-candidate(L,E,R),perm2(R,T).
%perm3(L - list, R - list)
%flow(i,o)
%perm3(l1...ln,r1...rn) = - perm3(l1...ln,r1...rn), test2Wrap(r1...rn)
perm3(L,R):-perm2(L,R),test2Wrap(R).
%wrapper(N - int, R - list)
%flow(i,o)
wrapper(0,[]).
wrapper(N,R):-buildReverse(N,R1),perm3(R1,R).
我很想知道是否有任何更简单的方法可以做到这一点,因为看来我比应该做的要复杂得多。
答案 0 :(得分:0)
好吧,我们来比较一下permutation/2
的SWI-Prolog实现(单击see the source的:-
按钮。有很多类型检查,然后解析为对此的调用谓词:
perm([], []).
perm(List, [First|Perm]) :-
select(First, List, Rest),
perm(Rest, Perm).
这看起来与您没什么不同;让我们看看select/3
和candidate/3
是否具有可比性:
select(X, [Head|Tail], Rest) :-
select3_(Tail, Head, X, Rest).
select3_(Tail, Head, Head, Tail).
select3_([Head2|Tail], Head, X, [Head|Rest]) :-
select3_(Tail, Head2, X, Rest).
因此,文档建议此处使用select3_/3
的目的实际上是使谓词在最后一个元素上具有确定性。实际上,除了参数的顺序之外,candidate/3
和select/3
之间的区别很小:
?- candidate([a,b,c], X, Y).
X = a,
Y = [b, c] ;
X = b,
Y = [a, c] ;
X = c,
Y = [a, b] ;
false.
?- select(X, [a,b,c], Y).
X = a,
Y = [b, c] ;
X = b,
Y = [a, c] ;
X = c,
Y = [a, b].
此处没有结尾false
。
有一个内置reverse/2
,因此不需要您编写代码。没有内置谓词可为您提供长度为N的整数列表。如果不使用reverse/2
,我的编码可能会略有不同,就像这样:
iota(N, L) :- iota(1, N, L).
iota(N, N, [N]).
iota(N0, N, [N0|NL]) :-
N0 < N,
succ(N0, N1),
iota(N1, N, NL).
过去,我们进入了您的wrapper/2
,perm3/2
,test2/2
,nrTest/3
谓词,但我不太了解您在做什么。但是我认为置换生成器本质上没有什么可怕的,您只需要利用它们存在的库例程即可(删除candidate/3
并使用select/3
,使用提供的reverse/2
真的有必要)。
Prolog的水平很高,但不是很简洁。高质量的Prolog代码 可以比同类过程代码短,但是(以我的经验)这与您可以使用的各种调用约定和关系思维有关,因为该语言本身并不是没那么短。 I wrote about this on my blog,并以another question为例。