순열의주기 수


23

고려 순열 정수의를 1, ..., n등이 하나 n = 6:

[5,2,4,3,6,1]

순열을에서 [1,2,3,4,5,6]로의 매핑으로 보는 경우 순열 [5,2,4,3,6,1]을 분리 된 주기로 분리 할 수 ​​있습니다 . 사이클은 서로 매핑되는 요소의 하위 집합입니다. 예를 들어에 1매핑되고 56매핑되고에 다시 매핑됩니다 1. 따라서 한주기는입니다 [1,5,6]. 다른주기는 [2][3,4]입니다. 따라서이 순열 의주기 수3입니다.

일반적으로 순열의주기는 고유하며 (순서대로), 순열의주기 수 n는에서 1까지 다양 합니다 n.

도전

비어 있지 않은 순열이 주어지면주기 수를 출력하십시오.

입력에 의해 형성된 배열 n의 정수 1, 2, ..., n, 여기서 n > 0. 각 정수는 정확히 한 번 발생합니다. 표시되는 순서는 위의 예와 같이 순열을 정의합니다.

배열 대신 목록, 숫자 사이에 구분 기호가있는 문자열, 각 숫자에 대한 별도의 입력 또는 합리적인 항목을 사용할 수 있습니다.

크기의 순열의 n경우 1 기반 정수 세트 대신 1...을 n사용하여 0 기반 세트 0..., n-1. 그렇다면 답변에 기재하십시오.

코드가 작동합니다 n까지 20적절한 시간에, 적은 일분 이상의 말한다.

코드 골프. 모든 내장이 허용됩니다.

테스트 사례

이것은 1 기반의 배열 입력을 가정합니다.

 [1] -> 1
 [3,2,1] -> 2
 [2,3,4,5,1] -> 1
 [5,2,4,3,6,1] -> 3
 [8,6,4,5,2,1,7,3] -> 2
 [4,5,11,12,7,1,3,9,10,6,8,2] -> 1
 [4,2,5,11,12,7,1,3,9,10,6,8] -> 5
 [5,8,6,18,16,9,14,10,11,12,4,20,15,19,2,17,1,13,7,3] -> 3
 [14,5,17,15,10,18,1,3,4,13,11,16,2,12,9,7,20,6,19,8] -> 7

관련

관련 문제 는 순열의 수가 아니라 순열의 실제주기를 요구합니다. 사이클 수만 요구하면 실제 사이클 생성을 회피하는 알고리즘이 짧아 질 수 있습니다.


내 질문에 신경 쓰지 마십시오 .0 기반 입력이 허용되는 질문에 명시되어 있습니다.
orlp

@orlp 그것은 빠르다! 나는 당신의 질문을 보지 못했습니다
Luis Mendo

입력 값으로 인덱스를 매핑 할 수 있습니까?
구리

1
@Copper 매핑의 도메인이 1, ..., n그 순서로 설정된 경우 예라고 생각합니다 . 맵핑이 입력이 될 수있는 방법을 명확히 할 수 있습니까? 데이터 구조입니까?
Luis Mendo

@LuisMendo 예, 파이썬과 같은 데이터 구조 dict입니다. {1: 2, 2: 1}대신 입력으로 사용 하고 싶습니다 [2, 1].
구리

답변:


12

J, 4 바이트

#@C.

이것은 순열이 0부터 시작한다고 가정합니다. C.직접 순열을 나타내는 목록이 지정된주기를 출력하는 내장 기능 을 사용합니다 . 그런 #구성 @이 그 목록에있는 사이클의 수를 반환에.

여기에서 시도하십시오.


1
부정 행위입니다! :)
orlp

1
나는 내장을 금지했다 :-D
Luis Mendo

2
내장은 사랑입니다. 내장은 삶입니다. 나는 내장이 금지되는 것이 더 재미있을 것이라고 동의합니다. 너무 많은 답변을하기 전에 지금 바로 규칙을 바꾸십시오.
마일

@ 마일리지, 그대로 두겠습니다. 잘 했어!
Luis Mendo

7

자바 스크립트, 99 98 바이트

이 솔루션은 배열과 해당 값이 0으로 인덱싱 된 것으로 가정합니다 (예 :) [2, 1, 0].

f=a=>{h={},i=c=0;while(i<a.length){s=i;while(!h[i]){h[i]=1;i=a[i]}c++;i=s;while(h[++i]);}return c}

설명

// assumes the array is valid and zero-indexed
var findCycles = (array) => {
    var hash = {};  // remembers visited nodes
    var index = 0;  // current node
    var count = 0;  // number of cycles
    var start;      // starting node of cycle

    // loop until all nodes visited
    while(index < array.length) {
        start = index;  // cache starting node

        // loop until found previously visited node
        while(!hash[index]) {
            hash[index] = 1;    // mark node as visited
            index = array[index];   // get next node
        }
        count++;    // increment number of cycles

        index = start + 1;  // assume next node is right after

        // loop until found unvisited node
        while(hash[index]) {
            index++;    // get next node
        }
    }

    return count;   // return number of cycles
};

3
PPCG에 오신 것을 환영합니다! 좋은 첫 대답! 이것은 또한 내 경험에서 본 최고의 대답 중 하나입니다. 좋은 일을 계속하십시오!
GamrCorps

와, 정말 고마워요! 실제로 JavaScript에서 람다를 수행하는 방법을 찾아야했습니다. 나는 아직 ES6에 익숙하지 않습니다.
kamoroso94

6

Mathematica, 45 바이트

Length@ConnectedComponents@Thread[Sort@#->#]&

그래프를 생성하고 연결된 구성 요소를 계산합니다.


6

수학, 37 28 27 바이트

#~PermutationCycles~Length&

9 바이트를 저장해 준 @alephalpha에게 감사하고 1 바이트 이상을 위해 @miles 감사합니다.


3
PermutationCycles[#,Length]&
alephalpha

3
오 깔끔하다. 나는 PermutationCycles출력의 헤드를 변경하기 위해 두 번째 논쟁을 취할 수 있다는 것을 몰랐다 . 다른 바이트를 저장하기 위해 접두사 표기법을 사용할 수도 있습니다 #~PermutationCycles~Length&.
마일

1
또한 귀하의 원래 솔루션과 관련하여 #&보다 약간 짧습니다 Identity. ;)
Martin Ender

6

파이썬, 77 69 67 바이트

f=lambda p,i=1:i and0 **p[i-1]+f(p[:i-1]+[0]+p[i:],p[i-1]or max(p))

(not p[i-1])으로 수행 할 수 있습니다0**p[i-1]
XNOR

5

젤리, 12 10 9 바이트

ị³$ÐĿ«/QL

@ Dennis 덕분에 1 바이트를 절약했습니다 .

1 기반 순열을 사용합니다. 이전 값을 유지하면서 이전 순열에 도달 할 때까지 순열을 반복적으로 적용하여 작동합니다. 변경 사항을 추적하여 해당 테이블의 열을 따라 모든 값에 대한 궤도를 만듭니다. 그런 다음 각 열의 최소 또는 최대를 찾아 해당주기의 레이블을 작성할 수 있습니다. 그런 다음 해당 레이블 목록을 중복 제거하고 길이를 가져와 분리 된 사이클 수를 지정하십시오.

여기에서 시도하십시오.

설명

ị³$ÐĿ«/QL  Input: permutation p
  $        Chain (ị³) as a monad
 ³           The input p
ị            For each value x, get the value at index x in p
   ÐĿ      Invoke it on p initially, and repeat it on its next value until it returns
           to a previous value and keep track of the results
           This will create a table where each column is the orbit of each value
     «/    Get the minimum value along each column of that table
       Q   Deduplicate
        L  Get the length and return

아주 좋은 접근법!
Luis Mendo

ị³$ÐĿ«/QL작동해야합니다.
Dennis

@ 데니스 와우, 그것은 깔끔한 트릭입니다! 각 사이클이 분리되어 있기 때문에 최대 / 분을 가져와 레이블로 사용하면 결과에 대해 중복 + 길이가 충분합니다.
마일

5

파이썬, 64 바이트

l=input()
for _ in l:l=[min(x,l[x])for x in l]
print len(set(l))

이 골프 코드는 관용적이고 읽을 수 있습니다. 0 인덱싱을 사용합니다.

각 값은 그것이 가리키는 것과 가리키는 값이 가리키는 것을보고 둘 중 작은 것을 가리 킵니다. 반복이 충분하면 각 요소는주기의 가장 작은 요소를 가리 킵니다. 그 다음에 지적 된 개별 요소의 수는 사이클 수입니다.

n반복 을 수행하면 충분합니다 . 또는 목록이 더 이상 변경되지 않을 때까지 반복 할 수 있습니다. 이 전략은 64 바이트의 동일한 길이의 재귀 함수를 제공했습니다.

f=lambda l,p=0:len(set(l*(l==p)))or f([min(x,l[x])for x in l],l)

65 바이트 감소

lambda l:len(set(reduce(lambda l,_:[min(x,l[x])for x in l],l,l)))

set(_)변환은 단축 될 수있다 {*_}2 바이트를 저장, 파이썬 3.5.


4

하스켈, 111 바이트

l!i|l!!i<0=l|1<2=(take i l++[-1]++drop(i+1)l)!(l!!i)
f(x:y)|x>=0=0|1<2=1+f y
c l|l==[-1|x<-l]=0|1<2=1+c(l!f l)

0 기반 인덱싱 사용


4
젠장, 당신은 좋은 프로그래밍 글꼴을 가지고있는 것이 좋습니다 :)1l!i|iIi!!1ll1|
orlp

@ orlp 그리고 111 바이트입니다! : O
grooveplex

4

Pyth, 9 바이트

l{mS.u@QN

0부터 시작하는 인덱스를 사용합니다. 온라인으로 사용해보십시오 .

작동 원리

  m         map for d in input:
    .u        cumulative fixed-point: starting at N=d, repeatedly replace N with
      @QN       input[N]
              until a duplicate is found, and return all intermediate results
   S          sort
 {          deduplicate
l           length

3

자바 스크립트 (ES6), 49 바이트

a=>a.reduce(g=(c,e,i)=>e<i?g(c,a[e],i):c+=e==i,0)

0부터 시작하는 인덱싱을 사용합니다. 설명 : 배열의 각 요소 reduce에서 내부 함수를 호출하는 데 사용됩니다 g. c사이클 횟수, e배열 요소, i배열 인덱스입니다. 요소가 인덱스보다 작 으면 잠재적 사이클입니다. 요소는 배열의 인덱스를 사용하여 순환에서 다음 요소를 재귀 적으로 찾습니다. 우리가 원래 색인으로 시작하거나 끝나는 경우 이것은 새로운주기이며주기 카운트를 증가시킵니다. 어느 시점에서든 색인보다 큰 값을 찾으면 나중에 해당주기를 계산합니다.


배열 [2,1,0,3,4,5]에서 코드를 실행하면 "최대 호출 스택 크기를 초과했습니다"라는 메시지와 함께 충돌이 발생했습니다.
kamoroso94

1
@ kamoroso94 죄송합니다. 오타가 들어갔습니다. 지금 수정해야합니다.
Neil

2

C, 90 바이트

f()가변 int배열, 1 기반 인덱싱으로 호출 합니다. 두 번째 매개 변수는 배열의 크기입니다. 이 함수는 사이클 수를 반환합니다.

i,j,c;f(a,n)int*a;{for(c=i=0;i<n;++i)for(j=0,c+=!!a[i];a[i];a[i]=0,i=j-1)j=a[i];return c;}

ideone에서 사용해보십시오 .

알고리즘 :

For each index
    If index is non-zero
        Increment counter
        Traverse the cycle, replacing each index in it with 0.

2

간격 , 30 바이트

간단하게, Cycles순열이 수행 될 집합 을 제공 하는 두 번째 인수 는 다음과 같습니다.

l->Size(Cycles(PermList(l),l))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.