【问题标题】:Single cycle permutations单周期排列
【发布时间】:2011-12-27 18:47:29
【问题描述】:

让我们对只有一个循环的数字 {1,2,3,4} 进行排列。例如它可以是:(2,3,4,1)。我想知道,如何使用 Prolog 生成所有这些排列?

我知道如何使用select 生成所有排列。

但我想不出如何只生成单循环(即单循环)排列。

谁能给我一个小小的提示或建议?

【问题讨论】:

  • 给定 n 个符号,有 (n-1) 个!这些符号的一个周期排列。为什么?
  • 了解第一类斯特林数,它计算具有 k 个不相交循环的 n 个元素的排列数。你应该看到复发,这应该对你有帮助,或者我可以解释你
  • 请不要从 Stack Overflow 中删除您的问题。有些人会花时间做出好的回答,尊重他们的工作。

标签: prolog permutation


【解决方案1】:

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

我们或许应该澄清一下,经常使用两种排列表示。 xyz 写道“我知道如何 [to] 生成所有排列 [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).

【讨论】:

    【解决方案2】:

    您不能使用该函数生成所有排列,并过滤掉那些不是“单周期排列”的排列吗? (由于我完全不清楚“单循环排列”是什么,恐怕我无法帮助编写该过滤器。)

    【讨论】:

      【解决方案3】:
      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.
      

      【讨论】:

      • 关于周期和一个周期的含义你可以在这里阅读:en.wikipedia.org/wiki/Permutation
      • 关于算法的一些事情:我们想要找到一个循环排列。所以我们有两个列表 L 和 P。P 是 L 只有一个循环的排列。因此,首先我们检查是否为真:permutation(L,P)。那么我们可以看到,L的头部和P的头部不应该是同一个数字。接下来,让我们取 [1,2,3,4] 和 [4,1,2,3],所以我们看到如果我们从 L 和 P 中选择 head,我们注意到 2,3,4 不能是[1,2,3] 的排列(因为定义了一个循环)。
      • 我添加了我认为正确的解决方案,因为现在我明白了循环是什么(最后:( )
      • 我基本上只是建立一个循环,如果这个循环不是列表的大小,那么排列就不是一个循环。你怎么看?
      • 它构建了一个循环,以便我们可以将其长度与列表进行比较,因为如果排列是单循环排列,则它的任何循环(它只有一个偶数)的长度都与列表...
      【解决方案4】:

      感谢hardmaththe answer 中的讨论,我能够理解它的全部内容。

      似乎解决方案很简单,将输入列表的尾部替换为它的排列以形成一个循环描述,然后将那个转换为它的列表表示 通过将每个元素与其下一个元素配对并在第一个组件上排序以获得第二个组件的列表作为结果列表:

      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.
      

      另见:

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-08
        • 1970-01-01
        • 1970-01-01
        • 2016-03-12
        • 1970-01-01
        • 2015-12-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多