我想获得3个元素的第n个排列。 例如。
列表= [1,2,3] n = 5
输出 [1,2,3,1,2] [1,2,3,2,1] ...
我不希望任何连续的相同元素如 [1,1,1,1,1] [1,2,3,3,2] ...
我尝试了很少可以得到完整的排列,无法想出如何得到我需要的东西。
varia_repp(N,RVaria):-varia_rep(N,[1,2,3],RVaria).
varia_rep(0,_,[]).
varia_rep(N,[H|L],RVaria):-N>0,N1 is N-1,delete(H,[H|L],_),varia_rep(N1,[H|L],RVaria).
或
perm(List,[H|Perm]):-delete(H,List,Rest),perm(Rest,Perm).
perm([],[]).
答案 0 :(得分:2)
执行此操作的一种方法(请注意,排列按字典顺序排列)是明确说明两个连续元素不能相同:
perm(1, Input, [Last]) :-
member(Last, Input).
perm(N, Input, [First,Second|Perm]) :-
N > 1, N0 is N-1,
member(First, Input),
dif(First, Second),
perm(N0, Input, [Second|Perm]).
?- perm(3,[a,b,c],R).
R = [a, b, a] ;
R = [a, b, c] ;
R = [a, c, a] ;
R = [a, c, b] ;
R = [b, a, b] ;
R = [b, a, c] ;
R = [b, c, a] ;
R = [b, c, b] ;
R = [c, a, b] ;
R = [c, a, c] ;
R = [c, b, a] ;
R = [c, b, c] ;
false.
您已使用swi-prolog标记了该问题。与其他主要的Prolog实现一样,它有一个谓词dif/2。你还可以在StackOverflow上找到关于dif / 2的一些有趣的讨论,有利有弊。总而言之,它构成了一个约束,即它的两个参数无法统一。它可以用于非实例化变量,在这种情况下,可以防止大量不必要的回溯,而无需任何明确的切割或额外的参数。
此外,不推荐使用delete / 3而选择select / 3。但是,这里只需要member / 2(因为你想重用元素)。
修改强>
正如评论中指出的那样,虽然dif / 2使事情变得更短,但可能会有点令人困惑。这是一个几乎相同的,稍微冗长的版本,没有dif / 2(对于较大的N来说,它的工作速度也快得多)。
p(N, Input, [First|Rest]) :-
N >= 1, N0 is N-1,
member(First, Input),
p(N0, Input, First, Rest).
p(0, _, _, []).
p(N, Input, Prev, [This|Rest]) :-
N > 0, N0 is N-1,
member(This, Input), This \= Prev,
p(N0, Input, This, Rest).
答案 1 :(得分:2)
根据您的样本判断,您不需要K个元素的第n个排列(样本中K = 3),而是N个元素的排列,其中N的列表构建为填充模板列表中的元素,然后过滤以排除连续的相等元素:
varia_rep(N, L, P) :-
build_rep(L, N, P0),
permutation(P0, P),
\+ append(_, [X,X|_], P).
build_rep(L, N, P0) :-
length(L, K),
findall(X, (between(1, N, I), J is ((I-1) mod K) + 1, nth1(J, L, X)), P0).
试验:
?- build_rep([1,2,3],5,P).
P = [1, 2, 3, 1, 2].
?- varia_rep(5,[1,2,3],P).
P = [1, 2, 3, 1, 2] ;
P = [1, 2, 3, 2, 1] ;
P = [1, 2, 1, 3, 2] ...