找到排列

时间:2011-12-27 18:47:29

标签: permutation

让我们对数字1,2,3,4进行排列,它只有一个周期。例如,它可以是:2,3,4,1。我想知道,我如何使用Prolog产生所有这些排列。 我知道如何使用函数选择生成所有排列。 但我无法提出一个想法,如何只产生一个周期的排列。

也许有人可以给我一个小提示或遗赠。

4 个答案:

答案 0 :(得分:0)

难道你不能使用该函数生成所有排列,并过滤掉那些不是“一周期排列”的排列吗? (因为我对'单循环排列'一点也不清楚,我恐怕无法帮助编写那个过滤器。)

答案 1 :(得分:0)

one-cycle([H|T], Permutation) :-
    permutation([H|T], Permutation),
    cycle(H, [H], [H|T], Permutation, Cycle),
    length(Cycle, CycleLength),
    length([H|T], ListLength),
    CycleLength =:= ListLength.

cycle/5谓词构建与传递它的第一个参数对应的循环。第二个参数是一个累加器,初始化为[FirstArgument],第三个和第四个是原始ListPermutation,最后一个是结果(包含循环元素的列表) )。

cycle(Current, Acc, List, Permutation, Cycle) :-

corresponds/4的调用检索取代排列中第一个参数的项目:

    corresponds(Current, List, Permutation, R),

如果这个项目在我们正在构建的周期中,那意味着我们已经完成了周期的构建,因此我们统一了Cycle和累加器(Acc)。

    (   member(R, Acc)
     -> Cycle = Acc

如果没有,我们继续用我们找到的相应项目递归调用我们的谓词,然后将它添加到累加器中,以便我们的构建周期现在可以保存它:

     ;  cycle(R, [R|Acc], List, Permutation, Cycle)).

corresponds(N, [N|_], [R|_], R) :-
    !.
corresponds(N, [_|L], [_|P], R) :-
    corresponds(N, L, P, R).

用法:

?- one-cycle([1, 2, 3, 4], P).
P = [2, 3, 4, 1] ;
P = [3, 1, 4, 2] ;
P = [3, 4, 2, 1] ;
P = [2, 4, 1, 3] ;
P = [4, 1, 2, 3] ;
P = [4, 3, 1, 2] ;
false.

答案 2 :(得分:0)

我的意见旨在作为直接生成单周期排列的提示,而不是生成所有排列并过滤掉由单个循环组成的排列。

我们或许应该澄清经常使用两种排列表示。 xyz写道“我知道如何生成所有排列[s],”大概意思就像我在this 2006 forum post中给出的代码。这里所有排列都是根据列表重新排列某些“标准顺序”列表中的项目的方式来表示的。

显然有N!各种排列。其中有多少是单周期排列?通过考虑对排列有用的另一种形式,即作为不相交循环的产物,可以很容易地回答这个问题。我们需要区分像(1,2,3,4)这样的循环和身份置换[1,2,3,4]。实际上,周期(1,2,3,4)将1到2,2到3,3到4和4映射回1,因此不是身份置换,而是[2,3,4,1]它的列表表示。

现在循环自身循环,所以我们选择开始循环表示法是任意的。例如,如果我们从1开始,则循环由以下N-1项的排序确定。这表明有(N-1)!形成单个循环的N个事物的排列(必然是长度N)。因此,我们可以足够容易地以循环形式生成所有单循环排列,然后问题减少到从该循环形式转换为排列的列表形式。 [注意,部分Mog解决了转向另一个方向:给定排列作为列表,找出包含在该排列中的循环(并查看它是否为全长)。]

这是我生成给定“标准订单”列表oneCycle(Identity,Permuted)的所有单周期列表排列的代码:

oneCycle([H|T],P) :-
    permute(T,S),
    oneCycle2permute([H|S],[H|T],P).

permute([ ],[ ]) :- !.
permute(L,[H|T]) :-
    omit(H,L,Z),
    permute(Z,T).

omit(H,[H|T],T).
omit(X,[H|T],[H|Z]) :-
    omit(X,T,Z).

oneCycle2permute(_,[ ],[ ]) :- !.
oneCycle2permute(C,[I|Is],[P|Ps]) :-
    mapCycle(C,I,P),
    oneCycle2permute(C,Is,Ps).

mapCycle([X],X,X) :- !.
mapCycle([H|T],X,Y) :-
    mapCycleAux(H,T,X,Y).

mapCycleAux(Y,[X],X,Y) :- !.
mapCycleAux(X,[Y|_],X,Y) :- !.
mapCycleAux(_,[X,Y|_],X,Y) :- !.
mapCycleAux(H,[_|T],X,Y) :-
    mapCycleAux(H,T,X,Y).

答案 3 :(得分:0)

感谢the document of JSthe answer中的讨论,我能够理解它的全部内容。

似乎解决方案非常简单,就是用排列置换输入列表的尾部以形成周期描述,然后将 that 转换成其 list表示形式< / em>,将每个元素与其下一个元素配对,然后对第一个元素进行排序,以将第二个元素放入结果列表:

single_cycled_permutation([A|B],    R) :-
  permutation(B,    P),
  cycle_pairs(A, A, P, CP),
  sort(                CP, SCP),
  maplist( pair,           SCP, _,  R).

pair( X-Y, X, Y).

cycle_pairs(  A, X, [Y|Z], [X-Y|W]) :-
  cycle_pairs(A, Y,    Z ,      W ).
cycle_pairs(  A, X, [   ], [X-A]  ).

要更轻松地查看周期,只需删除single_cycled_permutation中的最后一个目标:

single_cycled_pairs([A|B], SCP) :-
  permutation(B,    P),
  cycle_pairs(A, A, P, CP),
  sort(                CP, SCP).

测试:

21 ?- forall(  single_cycled_pairs([1,2,3,4], SCP), 
               (maplist(pair,SCP,_,R), write((SCP,R)), nl)).
[1-2,2-3,3-4,4-1],[2,3,4,1]
[1-2,2-4,3-1,4-3],[2,4,1,3]
[1-3,2-4,3-2,4-1],[3,4,2,1]
[1-3,2-1,3-4,4-2],[3,1,4,2]
[1-4,2-3,3-1,4-2],[4,3,1,2]
[1-4,2-1,3-2,4-3],[4,1,2,3]
true.

另请参阅: