Deranged! Combinatorics : 하위 요인 계산


25

subfactorial 또는 rencontres 번호 ( A000166는 ) 순열 조합론에 표시 팩토리얼 번호 유사한 일련의 숫자이다. 특히, N 번째 subfactorial ! N은 수주는 교란의 세트의 N 개의 요소. 변위는 요소가 동일한 위치에 남아 있지 않은 순열입니다. 하위 요인은 다음과 같은 반복 관계를 통해 정의 할 수 있습니다.

!n = (n-1) (!(n-1) + !(n-2))

사실, 계승에 대해 동일한 재발 관계가 유지되지만 하위 계승에 대해서는 다음과 같이 시작합니다.

!0 = 1
!1 = 0

(계승의 경우 물론 1! = 1 입니다.)

당신의 작업은 계산하는 것이다 ! n은 주어진 N .

규칙

계승과 마찬가지로 하위 계승도 매우 빠르게 자랍니다. 프로그램은 입력을 처리 할 수있는 경우는 괜찮 N 하도록을 ! N 언어의 기본 숫자 형식으로 표현 될 수있다. 그러나 알고리즘 은 이론적으로 임의의 n에 대해 작동해야합니다 . 즉, 통합 결과와 중간 값을 해당 언어로 정확하게 표현할 수 있다고 가정 할 수 있습니다. 유한 정밀도로 저장 또는 계산되는 경우 상수 e 는 제외됩니다 .

결과는 정확한 정수 여야합니다 (특히 과학적 표기법으로 결과를 근사화 할 수 없음).

사용자가 쓸 수 프로그램이나 함수를 상기의 어떠한 사용도 표준 방법 의 입력을 수신하고 출력을 제공한다.

모든 프로그래밍 언어를 사용할 수 있지만 이러한 허점 은 기본적으로 금지되어 있습니다.

이것은 이므로 바이트 단위로 측정 된 가장 짧은 유효한 답변이 이깁니다.

테스트 사례

n     !n
0     1
1     0
2     1
3     2
4     9
5     44
6     265
10    1334961
12    176214841
13    2290792932
14    32071101049
20    895014631192902121
21    18795307255050944540
100   34332795984163804765195977526776142032365783805375784983543400282685180793327632432791396429850988990237345920155783984828001486412574060553756854137069878601

답변:


19

Funciton , 336 바이트

바이트 수는 BOM을 사용한 UTF-16 인코딩을 가정합니다.

┌─╖┌─╖  ┌─╖ 
│f╟┤♭╟┐┌┤♭╟┐
╘╤╝╘═╝├┘╘═╝├────┐
 │┌─╖ │ ┌┐┌┘╔═╗╓┴╖
 ││f╟─┴┐└┴┼─╢0║║f║
 │╘╤╝  │  │ ╚═╝╙─╜
 │┌┴╖ ┌┴╖┌┴╖ ╔═╗
 ││+╟┐│×╟┤?╟┐║1║
 │╘╤╝│╘╤╝╘╤╝┘╚╤╝
 └─┘ └─┘  └───┘

이것은 f하나의 정수를 취하고 왼쪽으로 90도 회전하여 다른 정수를 출력 하는 함수 를 정의합니다 . 임의로 큰 입력에 작동합니다.

온라인으로 사용해보십시오!

이것이 Funciton이라는 점을 고려하면 상당히 빠릅니다 (TIO에서 n = 20은 약 14 초가 걸립니다). Funciton 인터프리터가 자동으로 함수를 기억한다고 생각하지 않기 때문에 주요 속도 저하는 이중 재귀에서 비롯됩니다.

불행하게도, 일부 모노 스페이스 글꼴은 라인을 정확하게 모노 스페이스하지 않거나 작은 간격을 삽입합니다. TIO 코드의 스크린 샷은 다음과 같습니다.

여기에 이미지 설명을 입력하십시오

나는 골프를 할 수 있다고 생각이 좀 더 예에서 조건을 변경하여 >0대상을 <1내가 숫자 문자를 재사용 할 수있는, 아니면 완전히 다른 수식을 사용하여,하지만 난 꽤있어 너무하고 조건의 가지를 교환 이미 얼마나 컴팩트한지에 만족합니다.

설명

기본 사례 ! (-1) =! 0 = 1을 사용하지만 기본적으로 도전에 주어진 재귀를 구현합니다 . n-1n-2 는 선행 기능으로 계산되며 중간 결과 n-1 은 세 곳에서 재사용됩니다. 그 이상은 많지 않으므로 제어 흐름을 빠르게 살펴 보겠습니다.

               ─┐
               ╓┴╖
               ║f║
               ╙─╜

이 함수의 입력 발광 기능 헤더 인 N 길게 연결된 라인. 이것은 즉시 T- 접합에 도달하여 단순히 값을 복제합니다.

        ┌┐┌┘╔═╗
        └┴┼─╢0║
          │ ╚═╝

0상자는 숫자 문자입니다. 4 방향 접합은 두 가지 기능을 계산합니다. 하단을 이끄는 경로는 0 <n을 계산 하며, 기본 사례를 결정하는 데 사용됩니다. 왼쪽으로가는 경로는 0 << n (왼쪽 시프트)을 계산 하지만 Starkov 구문 으로이 값을 버립니다 .

         ┌┴╖ ╔═╗
         ┤?╟┐║1║
         ╘╤╝┘╚╤╝
          └───┘

우리는 이것을 3 방향 조건부로 이끈다 ?. 값이 false이면 상수 result를 반환합니다 1. 의 오른쪽 끝 ?은 기능 출력입니다. 여기서는 f프로그램의 나머지 부분에서 입력 및 출력의 상대적 방향 이 더 편리 하도록 여기를 180도 돌리고 있습니다 .

조건이 true이면 다른 값이 사용됩니다. 이 지점으로 이어지는 경로를 살펴 봅시다. (Funciton의 평가는 실제로 게 으르므로이 분기가 필요하지 않은 경우 평가되지 않으므로 처음부터 재귀가 가능합니다.)

        ┌─╖ 
      ┐┌┤♭╟┐
      ├┘╘═╝
      │
     ─┴┐

다른 브랜치에서는 먼저 n-1을 계산 한 다음 경로를 두 번 분할하여 값의 사본 3 개를 얻습니다 (하나는 반복 계수에 대한 것, 첫 번째 하위 요인에 대한 것, 하나는 n-2에 대한 것 ).

┌─╖┌─╖
│f╟┤♭╟
╘╤╝╘═╝
 │┌─╖
 ││f╟
 │╘╤╝
 │┌┴╖
 ││+╟
 │╘╤╝
 └─┘ 

내가 말했듯이, 우리는 한 사본을 다른 사본으로 다시 줄인 다음 n-1n-2를 재귀 적으로 공급 f하고 마지막으로 두 결과를에 추가합니다 +.

       ┐
       │
      ┌┴╖
     ┐│×╟
     │╘╤╝
     └─┘

남은 것은 n-1! (n-1) +! (n-2) 를 곱하는 것 입니다.


13

오아시스 , 5 바이트

Martin이 제공 한 공식을 사용합니다. 암호:

+n<*X

해부 된 버전 :

+n<*

a(0) = 1a(1) = 0.

설명 a(n) =:

+       # Add the previous two terms, a(n - 1) + a(n - 2).
 n<     # Compute n - 1.
   *    # Multiply the top two elements.

온라인으로 사용해보십시오!


멋진 트릭을 사용하여 X:-) BTW, 당신이 구현 않은 아직? 요즘 우리는 단지 초기 값을 변경하는 것만으로는 벗어날 수 없습니다
Luis Mendo

@LuisMendo 그렇습니다! 그것은 명령 플래그로 사용되는 ( 여기 에서 정보 페이지로 연결되는 링크입니다). 제안 해 주셔서 감사합니다 :).
Adnan


7

젤리 , 7 바이트

R=Œ!Ḅċ0

이 접근 방식은 변형을 구성하므로 다소 느립니다.

온라인으로 사용해보십시오!

작동 원리

R=Œ!Ḅċ0  Main link. Argument: n

R        Range; yield [1, ..., n].
  Œ!     Yield all permutations of [1, ..., n].
 =       Perform elementwise comparison of [1, ..., n] and each permutation.
    Ḅ    Unbinary; convert each result from base 2 to integer. This yields 0 for
         derangements, a positive value otherwise.
     ċ0  Count the number of zeroes.

7

Brachylog (2), 11 바이트

⟦₁{p:?\≠ᵐ}ᶜ

온라인으로 사용해보십시오!

설명

이것은 기본적으로 사양을 영어에서 Brachylog로 직접 변환하는 것입니다 (따라서 특정 목록의 정렬 수 찾기와 같이 사양의 작은 변경 사항을 처리하도록 쉽게 수정할 수 있다는 장점이 있습니다).

⟦₁{p:?\≠ᵐ}ᶜ
⟦₁           Start with a list of {the input} distinct elements
  {      }ᶜ  Then count the number of ways to
   p         permute that list
      \      such that taking corresponding elements
    :?       in {the permutation} and the list of distinct elements
       ≠     gives different elements
        ᵐ    at every position

5

내장 솔루션이있는 언어

다음 XNOR의 제안 이 사소한 솔루션을 기반으로하는에 CW 응답 단일 내장 subfactorial를 계산 또는 모든 교란의 편집해야 생성 할 수 있습니다.

수학, 12 바이트

Subfactorial

한숨 Mathematica ...
epicbob57

5

파이썬 3 , 35 32 바이트

f=lambda n:n<1or(-1)**n+n*f(n-1)

이것은 @Laikoni의 Haskell answer 의 반복 관계 ! n = n! (n-1) + (-1) n 을 기본 사례 ! 0 = 1로 사용 합니다.

온라인으로 사용해보십시오!


여기 에 주어진 다른 방정식을 사용할 수도 있다고 생각합니다 f=lambda n:n<1or n*f(n-1)+(-1)**n.이 경우 2 바이트가 절약 됩니다.
Adnan

1
약간의 순서 변경이있는 3 바이트 ;)
Dennis

1
이 재발의 재미있는 부분은 기본 사례를 (으)로 되 돌리면 n=-1사용하는 값이 전혀 중요하지 않다는 것입니다. 이는 일부 언어에 유용 할 수 있습니다 (예 : Mathematica에서는 바이트를 저장 한 경우 실제로 정의되지 않은 상태로 둘 수 있음).
Martin Ender

5

M , 9 바이트

o2!÷Øe+.Ḟ

당신이를 제거하여 볼 수 있듯이 , M은 상징적 인 수학을 사용하기 때문에 더 정밀 문제가 없을 것입니다.

온라인으로 사용해보십시오! 게시 된 가장 짧은 솔루션은 아니지만 빠릅니다 .

작동 원리

o2!÷Øe+.Ḟ  Main link. Argument: n

o2         Replace input 0 with 2, as the following formula fails for 0.
  !        Compute the factorial of n or 2.
   ֯e     Divide the result by e, Euler's natural number.
      +.   Add 1/2 to the result.
        Ḟ  Floor; round down to the nearest integer.

5

MATL , 9 8 바이트

:tY@-!As

@Dennis의 Jelly 답변 과 유사하게 , 이것은 실제로 순열을 만들고 그것들 중 얼마나 많은 수를 세는지를 계산합니다. 너무 느립니다.

온라인으로 사용해보십시오!

:     % Input n implicitly: Push [1 2 ... n]
t     % Duplicate 
Y@    % Matrix of all permutations, each on a row
-     % Element-wise subtract. A zero in a row means that row is not a derangement
!     % Transpose
A     % True for columns that don't contain zeros
s     % Sum. Implicitly display

3

수학 , 21 바이트

Round@If[#>0,#!/E,1]&

나는 이것에 매우 익숙하며 내가하고있는 일을 모른다.

온라인으로 사용해보십시오!


1
동일한 바이트 수의 두 가지 대안 : Round[(#/. 0->2)!/E]&±0=1;±n_:=Round[n!/E](Mathematica와 같은 소스 파일에 대해 Mathics가 단일 바이트 인코딩을 지원하는지 여부는 알 수 없지만)
Martin Ender

첫 번째는 잘 작동 하지만 (내가 하는 일을 알고 있다고 생각 하지만) Mathics는 ±두 번째 것을 지원하지 않는 것 같습니다 . 와 함께 작동 f하지만 2 바이트의 비용이 듭니다.
Dennis

같은 바이트 수의 다른 것 : Round[#!/E]+1-Sign@#&. 성가신 초기 값 ...!
Greg Martin

3

루비, 27 바이트

f=->n{n<1?1:n*f[n-1]+~0**n}

~0**n보다 짧습니다 (-1)**n!


3

CJam (10 바이트)

1qi{~*)}/z

온라인 데모 .

이것은 !n = n !(n-1) + (-1)^n내가 재귀를 사용하는데 , 이것은 내가 n! / eOEIS에서 파생 되었고 이미 발견되었습니다.

해부

루프는를 계산 (-1)^n !n하므로 끝에 절대 값을 가져와야합니다.

1     e# Push !0 to the stack
qi{   e# Read an integer n and loop from 0 to n-1
  ~   e#   Bitwise not takes i to -(i+1), so we can effectively loop from 1 to n
  *   e#   Multiply
  )   e#   Increment
}/
z     e# Take the absolute value


2

MATLAB, 33 바이트

@(n)(-1)^n*hypergeom([1 -n],[],1)

Mehdi Hassani 의 Derangements and applications 섹션 3에있는 공식을 사용하는 Anonympus 함수 .

사용 예 :

>> @(n)(-1)^n*hypergeom([1 -n],[],1)
ans = 
    @(n)(-1)^n*hypergeom([1,-n],[],1)
>> ans(6)
ans =
   265

2

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

f=n=>!n||n*f(n-1)-(~n%2|1)

@Laikoni의 답변에서 되풀이 관계를 사용합니다. ES7에서는 +(-1)**n대신을 사용하여 바이트를 저장할 수 있습니다 -(~n%2|1).


2

포스트 스크립트, 81 76 69 바이트

다음은 두 공식의 구현입니다.

n * f (n-1) + (-1) ^ n

/ f {dup 0 eq {pop 1} {dup dup 1 sub f mul exch 2 mod 2 mul 1 sub sub} ifelse} def

/f{dup 0 eq{pop 1}{dup dup 1 sub f mul -1 3 2 roll exp add}ifelse}def

그 버전은 float를 출력합니다. 정수를 출력해야하는 경우 :

/f{dup 0 eq{pop 1}{dup dup 1 sub f mul -1 3 2 roll exp cvi add}ifelse}def

무게는 73 바이트입니다.

다른 공식은 81 바이트입니다.

(n-1) * (f (n-1) + f (n-2))

/f{dup 1 le{1 exch sub}{1 sub dup f exch dup 1 sub f 3 -1 roll add mul}ifelse}def

이러한 함수는 스택에서 인수를 가져 와서 결과를 스택에 둡니다.

파일 또는 대화식 PostScript 프롬프트 (예 : GhostScript)에서 기능을 테스트 할 수 있습니다.

0 1 12{/i exch def [i i f] ==}for

산출

[0 1]
[1 0.0]
[2 1.0]
[3 2.0]
[4 9.0]
[5 44.0]
[6 265.0]
[7 1854.0]
[8 14833.0]
[9 133496.0]
[10 1334961.0]
[11 14684570.0]
[12 176214848.0]

다음은 출력을 화면이나 프린터 페이지로 렌더링하는 완전한 PostScript 파일입니다. (PostScript의 주석은로 시작합니다 %).

%!PS-Adobe-3.0

% (n-1)*(f(n-1)+f(n-2))
% /f{dup 1 le{1 exch sub}{1 sub dup f exch dup 1 sub f 3 -1 roll add mul}ifelse}def

% n*f(n-1)+(-1)^n
/f{dup 0 eq{pop 1}{dup dup 1 sub f mul -1 3 2 roll exp add}ifelse}def

% 0 1 12{/i exch def [i i f] ==}for

/FS 16 def              %font size
/LM 5 def               %left margin
/numst 12 string def    %numeric string buffer

/Newline{currentpoint exch pop FS sub LM exch moveto}def
/Courier findfont FS scalefont setfont
LM 700 moveto

(Subfactorials) Newline
0 1 12{
    dup numst cvs show (: ) show f numst cvs show Newline
}for
showpage
quit

1
-1 3 2 roll exp보다 조금 짧습니다 exch 2 mod 2 mul 1 sub.
피터 테일러

@PeterTaylor 그렇습니다! :) 나는 잊어 버렸습니다 exp: oops : 그러나 float을 반환 하므로 질문에 맞게 정수를 출력해야 한다고 생각 합니다.
PM 2Ring

1
나는 아직도 당신이 들어 와서 cvi절약 할 수 있다고 생각합니다 . (참고 : 테스트를 거치지 않았지만 문서를 읽으면 작동해야한다고 생각합니다).
피터 테일러

@PeterTaylor 예, cvi작동하며 여전히 이전 버전보다 짧습니다.
PM 2Ring

1

PHP, 69 바이트

function f($i){return$i>1?$i*f($i-1)+(-1)**$i:1-$i;}echo f($argv[1]);

이 방법으로 사용하십시오 a(n) = n*a(n-1) + (-1)^n


1
전체 프로그램이 아닌 함수 만 제공하면되므로 마지막 17자를 삭제할 수 있습니다. 특수한 입력 1을 사용하지 않음으로써 추가 절약이 가능합니다. 두 절약이 47 바이트로 줄었다 고 생각합니다.
피터 테일러

1

PHP, 50 44

for(;$i++<$argn;)$n=++$n*$i-$i%2*2;echo$n+1;

로 실행 echo <n> | php -nR '<code>

의 아름다움은 a(n) = n*a(n-1) + (-1)^n단지 이전의 값에 따라 달라집니다 것입니다. 이를 통해 재귀 대신 반복적으로 구현할 수 있습니다. 이것은 긴 함수 선언을 저장합니다 .

@Titus에서 -6 바이트 감사 !


-1 바이트 : $i++<$argv[1]. -2 바이트 : for(;$i++<$argv[1];)$n=++$n*$i-$i%2*2;echo$n+1;. (-3와 바이트 -R$argn.)
디도

@Titus 누군가 지루해? : D -R및에 대한 예를 들어 주 $argn시겠습니까?
Christoph

1
지루하지는 않지만 골프를 열망합니다. php.net/manual/de/features.commandline.options.php를 참조하십시오 : echo <input> | php -nR '<code>'. 예 : codegolf.stackexchange.com/a/113046
Titus

1
@Titus 내가 올바르게 얻었습니까? ;-)
Christoph

0

Mathematica, 40 바이트

±0=1;±1=0;±n_:=(n-1)(±(n-1)+±(n-2))

기본 ISO 8859-1 인코딩에서 31 바이트로 제공됩니다.


0

C, 34 바이트

a(n){return n?n*a(n-1)-n%2*2+1:1;}

설명:

a(n){                            } define a function called a of n
     return                     ;  make the function evaluate to...
            n?                :1   set the base case of 1 when n is 0
              n*a(n-1)             first half of the formula on the page
                      -n%2*2+1     (-1)**n

0

R, 47 바이트

n=scan();`if`(!n,1,floor(gamma(n+1)/exp(1)+.5))

Mego의 답변 과 동일한 공식을 사용합니다 .

다른 방법, PerMallows라이브러리를 사용하는 52 바이트

n=scan();`if`(!n,1,PerMallows::count.perms(n,n,'h'))

0

실제로 18 바이트

;!@ur⌠;!@0Dⁿ/⌡MΣ*≈

온라인으로 사용해보십시오!

설명:

;!@ur⌠;!@0Dⁿ/⌡MΣ*≈
;                   duplicate input
 !                  n!
  @ur               range(0, n+1) (yields [0, n])
     ⌠;!@0Dⁿ/⌡M     for each i in range:
      ;               duplicate i
       !              i!
        @0Dⁿ          (-1)**i
            /         (-1)**i/i!
               Σ    sum
                *   multiply sum by n!
                 ≈  floor into int

실제로 더 정밀한 경우 작동하는 12 바이트 버전 :

;!╠@/1½+L@Y+

온라인으로 사용해보십시오!

다른 모든 답변 (게시물 기준)과 달리이 솔루션은 재귀 수식이나 합산 수식을 사용하지 않습니다. 대신 다음 공식을 사용합니다.

변위 공식

이 공식은 실제로 다음과 같이 구현하기가 비교적 쉽습니다.

!╠@/1½+L
!         n!
 ╠        e
  @/      divide n! by e
    1½+   add 0.5
       L  floor

이제 유일한 문제는 수식이 positive 만 유지한다는 것 n입니다. 사용하려고 n = 0하면 수식이 잘못 생성 0됩니다. 그러나 이것은 쉽게 수정됩니다. 부울 부정을 입력에 적용하고이를 공식의 출력에 추가하면 모든 음이 아닌 올바른 출력이 제공됩니다 n. 따라서 해당 수정 프로그램은 다음과 같습니다.

;!╠@/1½+L@Y+
;             duplicate input
 !            n!
  ╠           e
   @/         divide n! by e
     1½+      add 0.5
        L     floor
         @Y   boolean negate the other copy of the input (1 if n == 0 else 0)
           +  add

나를 위해 부정적인 대답을 계속합니다 ...
Leaky Nun

@LeakyNun 정밀한 한계 때문입니다. 큰 입력 (약 n = 100)의 경우 (-1)**n/n!배정도 IEEE 754 부동 소수점으로 표현할 수 없습니다. 도전 과제에 따르면 괜찮습니다.
Mego

심지어 n=4...
Leaky Nun

@LeakyNun 오. 왜 바닥 구분을 사용했는지 모르겠습니다. 지금 고쳐
Mego



0

Alice , 20 18 바이트

1/o
k\i@/&wq*eqE+]

온라인으로 사용해보십시오!

설명

이러한 용도에서 재귀 Laikoni의 대답 , ! N = N! (N-1) + (-1) N . Funciton 답변과 유사하게 기본 사례 ! (-1) = 1을 사용하고 있습니다. 로 스택에 1 을 넣습니다 1.. 그럼 이건 ...

.../o
...\i@/...

...은 일반적인 십진 I / O 프레임 워크입니다. 주요 코드는 실제로

&wq*eqE+]k

세분화 :

&w    Push the current IP address N times to the return address stack, which
      effectively begins a loop which will be executed N+1 times.
  q     Push the position of the tape head, which we're abusing as the
        iterator variable n.
  *     Multiply !(n-1) by n.
  e     Push -1.
  q     Retrieve n again.
  E     Raise -1 to the nth power.
  +     Add it to n*!(n-1).
  ]     Move the tape head to the right.
k     Jump back to the w, as long as there is still a copy of the return
      address on the return address stack. Otherwise, do nothing and exit
      the loop.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.