Dengesiz! Kombinatorik: Alt Faktörü Hesapla


25

Subfactorial veya rencontres numaraları ( A000166 ) permütasyon kombinatorik görünür faktör numaralarına benzer bir sayı dizisi bulunmaktadır. Özellikle n inci subfactorial ! N sayısını verir düzensizliklerinde bir dizi n elemanları. Bir düzensizlik, hiçbir elemanın aynı konumda kalmadığı bir permütasyondur. Alt faktör aşağıdaki tekrarlama ilişkisi ile tanımlanabilir:

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

Aslında, aynı yineleme ilişkisi faktoring için de geçerlidir ancak alt faktörler için bizden başlarız:

!0 = 1
!1 = 0

(Faktoring için elbette 1! = 1 olurdu .)

Göreviniz hesaplamak ! N , verilen n .

kurallar

Faktoring gibi, alt faktör de çok hızlı büyür. Programınızın yalnızca n girişlerini işleyebilmesi gayet iyi, öyle ki ! N , kendi dilinizin yerel sayı türüyle gösterilebilir. Ancak, algoritma keyfi için teori çalışmalarında zorunluluk n . Bu, integral sonuçların ve ara değerin tam olarak diliniz tarafından temsil edilebildiğini varsayabilirsin . Bunun e sabitini hariç tuttuğunu unutmayın.Bunun, sonlu hassasiyetle saklanması veya hesaplanması durumunda .

Sonucun tam bir tamsayı olması gerekir (özellikle sonucu bilimsel gösterimle belirtemezsiniz).

Bir program veya fonksiyon yazabilir ve standart yöntemlerden herhangi birini kullanabilirsiniz. giriş alma ve çıkış sağlama .

Herhangi bir programlama dilini kullanabilirsiniz , ancak bu boşlukların varsayılan olarak yasak olduğunu unutmayın .

Bu , yani en kısa geçerli cevap - bayt olarak ölçülen - kazanır.

Test Kılıfları

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

Yanıtlar:


19

Funciton , 336 bayt

Bayt sayısı, BOM ile UTF-16 kodlaması yaptığını varsayar.

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

Bu, bir ftamsayı alan ve sola 90 derecelik bir dönüşle başka bir tamsayı çıkaran bir fonksiyon tanımlar . Keyfi olarak büyük girdiler için çalışır.

Çevrimiçi deneyin!

Bunu düşününce Funciton, makul bile hızlı (n = 20 yaklaşık 14 saniye sürüyor). Asıl yavaşlama, çift özyinelemeden geliyor, çünkü Funciton yorumlayıcısının işlevleri otomatik olarak hafızaya aldığını sanmıyorum.

Maalesef, bazı monospaced fontlar , çizgileri düzgün şekilde ve / veya satırları arasında küçük boşluklar eklemiyor. İşte tüm güzelliğiyle TIO’nun kodunun bir ekran görüntüsü:

görüntü tanımını buraya girin

Bunun golf mümkün olabileceğini düşünüyorum bu biraz daha, örneğin koşul'u değiştirerek >0için <1ben sayı literal yeniden olabilir, ya da belki tamamen farklı bir formül kullanarak, ama ben oldukça değilim ki, koşullu dallarını takas zaten ne kadar kompakt olduğu için mutluyum.

açıklama

Bu temel olarak meydan okumada verilen özyinelemeyi uygular, ancak temel durumu kullanır ! (- 1) =! 0 = 1 . n-1 ve n-2 , önceki işlevle hesaplanır ve ara sonuç n-1 , üç yerde yeniden kullanılır. Çok fazla bir şey yok, o yüzden hemen kontrol akışından geçeceğim:

               ─┐
               ╓┴╖
               ║f║
               ╙─╜

Bu fonksiyonun giriş yayan fonksiyon başlığı olup n bağlı uzun süre hattı. Bu, hemen değeri kopyalayan T-kavşağına ulaşır.

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

0Kutu sadece bir sayısal hazır olduğunu. 4 yollu bir kavşak iki işlevi hesaplar: alttan aşağı giden yol , temel durumu belirlemek için kullanacağımız 0 <n değerini hesaplar . Ayrı ayrı sola giden yol 0 << n (sola kaydırma) olarak hesaplanır, ancak bu değeri Starkov yapısıyla atarız .

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

Bunu üç yollu koşullara yönlendiriyoruz ?. Değer yanlışsa, sabit sonucu döndürürüz 1. Sağdaki gevşek uç ?, fonksiyon çıkışıdır. Burada 180 derece döndürüyorum, böylece girişin ve çıkışın göreceli yönü fprogramın geri kalanında daha uygundur.

Koşul doğruysa, diğer değer kullanılacaktır. Bu dala yol açan yola bakalım. (Funciton'un değerlendirmesinin gerçekte tembel olduğunu ve bu dalın gerekli olmadığında asla değerlendirilmeyeceğini unutmayın; bu da özyinelemeyi mümkün kılar.)

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

Diğer branşta önce n-1'i hesaplar ve sonra yolu iki kere böleriz, böylece değerin üç kopyasını elde ederiz (biri nüks katsayısı için, biri ilk alt faktör için, n-2 için son ).

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

Dediğim gibi, biz bir başkasıyla yeniden kopyalamak azaltma sonra ikimiz de beslemek, n-1 ve n-2 yinelemeli için fve nihayet bir araya iki sonucu ekleyin +.

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

Geriye Bütün bu çarpın etmektir n-1 tarafından ! (N-1) +! (N-2) .


13

Vaha , 5 bayt

Martin tarafından verilen formülü kullanır. Kod:

+n<*X

Diseksiyon versiyonu:

+n<*

ile a(0) = 1ve a(1) = 0.

Açıklama, a(n) =:

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

Çevrimiçi deneyin!


Güzel hile kullanarak X:-) BTW, uygulamak mı bu henüz? Bu günlerden biri, başlangıçtaki değerleri değiştirerek kurtulmayacağız
Luis Mendo

@LuisMendo Evet yaptım! Bir komut bayrağı olarak kullanılır ( burada bilgi sayfasına bir link verilmiştir). Öneriniz için teşekkür ederim :).
Adnan


7

Jöle , 7 bayt

R=Œ!Ḅċ0

Bu yaklaşım düzenlemeleri inşa ediyor, bu yüzden oldukça yavaş.

Çevrimiçi deneyin!

Nasıl çalışır

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 bayt

⟦₁{p:?\≠ᵐ}ᶜ

Çevrimiçi deneyin!

açıklama

Bu, temelde sadece İngilizceden Brachylog'a yapılan çevirinin doğrudan çevirisidir (ve bu nedenle, belirli bir listedeki düzenleme sayısını bulma gibi özelliklerde yapılan küçük değişikliklerle başa çıkmak için kolayca değiştirilebilme avantajına sahiptir).

⟦₁{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

Yerleşik çözümleri olan diller

Xnor'ın önerisini takiben , bu, alt faktörleri hesaplamak ya da tüm düzenlemeleri oluşturmak için tek bir yerleşike dayanan önemsiz çözümlerin düzenlenmesi gereken bir CW cevabıdır.

Mathematica, 12 bayt

Subfactorial

nefes Mathematica ...
epicbob57

5

Python 3 , 35 32 bayt

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

Bu kullanımlar nüks ilişkisi ! N = n! (N-1) + (1) n- dan Laikoni en Haskell cevap @ temel durum ile, ! 0 = 1 .

Çevrimiçi deneyin!


Ben de verilen diğer denklemi kullanabilirsiniz düşünüyorum burada iki bayt tasarrufu sağlamış olacağız: f=lambda n:n<1or n*f(n-1)+(-1)**n.
Adnan

1
Biraz yeniden sıralama ile üç bayt. ;)
Dennis,

1
Bu yinelemenin eğlenceli kısmı, taban çantasını geri n=-1iterseniz, hangi değeri kullandığınızın bir önemi yoktur. Bu, bazı diller için faydalı olabilir (örneğin, Mathematica'da, herhangi bir bayt kurtardıysa, tanımsız bırakabilirsiniz).
Martin Ender

5

M , 9 bayt

o2!÷Øe+.Ḟ

Bunu kaldırarak görebileceğiniz gibi , M sembolik matematiği kullanır, dolayısıyla hiçbir hassas problem olmaz.

Çevrimiçi deneyin! Yayınlanan en kısa çözüm değil, hızlı .

Nasıl çalışır

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 bayt

:tY@-!As

@Dennis 'Jelly cevabına benzer şekilde , bu aslında permütasyonları oluşturur ve kaç tanesinin düzensizlik olduğunu sayar; bu yüzden yavaş.

Çevrimiçi deneyin!

:     % 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

Matematik , 21 bayt

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

Bunun için çok yeniyim ve ne yaptığım hakkında hiçbir fikrim yok ...

Çevrimiçi deneyin!


1
Aynı bayt sayısında iki alternatif: Round[(#/. 0->2)!/E]&ve ±0=1;±n_:=Round[n!/E](Mathics'in yaptığı gibi kaynak dosyalar için Mathics'in tek baytlık kodlamaları destekleyip desteklemediğini bilmeme rağmen).
Martin Ender

İlki iyi çalışıyor ( bence ne yaptığını biliyorum), ama Matematik ±ikincisini desteklemiyor gibi görünüyor . fİki bayt pahasına, ancak işe yarayacaktı .
Dennis,

Aynı bayt başka bir saymak: Round[#!/E]+1-Sign@#&. Can sıkıcı başlangıç ​​değerleri ...!
Greg Martin

3

Ruby, 27 bayt

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

~0**ndaha kısa (-1)**n!


3

CJam (10 bayt)

1qi{~*)}/z

Çevrimiçi demo .

Bu !n = n !(n-1) + (-1)^ntüretilmiş nüks kullanırn! / e ve daha sonra OEIS’te olduğunu keşfettiğim .

teşrih

Döngü hesaplanır (-1)^n !n, bu yüzden sonunda mutlak değeri almamız gerekir:

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

05AB1E , 8 bayt

΃N*®Nm+

Çevrimiçi deneyin!

açıklama

Î         # initialize stack with 0 and input
 ƒ        # for N in range [0 ... input]:
  N*      # multiply top of stack with N
    ®Nm   # push (-1)^N
       +  # add

2

MATLAB, 33 bayt

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

Derangements Bölüm 3'teki formülü kullanan anonympus işlevi ve uygulamalar Mehdi Hassani tarafından yapılan .

Örnek kullanım:

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

2

JavaScript (ES6), 26 bayt

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

@ Laikoni'nin cevabından yineleme ilişkisini kullanır. ES7'de, +(-1)**nyerine bir bayt kaydedebilirsiniz -(~n%2|1).


2

PostScript, 81 76 69 bayt

İşte her iki formülün uygulamaları.

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

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

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

Bu sürüm bir şamandıra çıktılar. Bir tamsayı çıkarmak gerekirse:

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

hangi 73 byte ağırlığında.

Diğer formül biraz daha uzun: 81 bayt.

(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

Bu işlevler argümanlarını yığından alır ve sonucu yığında bırakır.

İşlevleri bir dosyada veya etkileşimli bir PostScript isteminde (örn. GhostScript) test edebilirsiniz.

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

çıktı

[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]

İşte çıktıyı ekrana veya bir yazıcı sayfasına veren tam bir PostScript dosyası. (PostScript'teki yorumlar ile başlar %).

%!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 expadil bir bit daha kısa exch 2 mod 2 mul 1 sub.
Peter Taylor

@PeterTaylor Öyleyse öyle! :) Unuttum exp: oops: Ancak, bu bir kayan nokta döndürür ve sanırım soruya uyması için bir tamsayı çıkarmam gerekiyor.
PM 2Ring

1
Sanırım hala içeri cvigirip tasarruf yapabilirsiniz. (Not: denenmemiş, ancak doktora okumaktan çalışması gerektiğini düşünüyorum).
Peter Taylor

@PeterTaylor Evet, cviçalışıyor ve hala önceki sürümümden daha kısa.
PM 2Ring

1

PHP, 69 Bayt

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

bu yolu kullan a(n) = n*a(n-1) + (-1)^n


1
Tam programı değil, sadece işlevi vermeniz gerekir, böylece son 17 karakteri bırakabilirsiniz. Özel muhafaza girişi değil, başka bir tasarruf var. 1. İki tasarrufun bunu 47 bayta indirdiğini düşünüyorum.
Peter Taylor

1

PHP, 50 44

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

İle koş echo <n> | php -nR '<code>

Bunun güzelliği a(n) = n*a(n-1) + (-1)^nsadece önceki değere bağlı olmasıdır. Bu, yinelemeli yerine yinelemeli olarak uygulanmasını sağlar. Bu, uzun işlev bildirimi kaydeder .

-Titus @ 6 byte . Teşekkürler !


-1 bayt: $i++<$argv[1]. -2 bayt: for(;$i++<$argv[1];)$n=++$n*$i-$i%2*2;echo$n+1;. (-3 bayt -Rve $argn.)
Titus

@Titus birisi sıkıldı mı? : D için bana bir örnek verir misin -Rve $argn?
Christoph

1
Sıkıldım, ama golf oynamak için istekli. Php.net/manual/de/features.commandline.options.php adresini ziyaret edin: echo <input> | php -nR '<code>' örnek: codegolf.stackexchange.com/a/113046
Titus

1
@Titus doğru anladım mı? ;-)
Christoph

0

Mathematica, 40 bayt

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

Varsayılan ISO 8859-1 kodlaması altında 31 byte'ta geliyor.


0

C, 34 bayt

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

Açıklama:

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 bayt

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

Mego'nun cevabıyla aynı formülü kullanır .

Alternatif yöntem, PerMallowskütüphaneyi kullanarak 52 bayt

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

0

Aslında , 18 bayt

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

Çevrimiçi deneyin!

Açıklama:

;!@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

Aslında daha fazla hassasiyet varsa çalışacak 12 baytlık bir sürüm:

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

Çevrimiçi deneyin!

Tüm diğer cevapların aksine (gönderimden itibaren), bu çözüm ne özyinelemeli formülü ne de toplam formülünü kullanmaz. Bunun yerine, aşağıdaki formülü kullanır:

düzenleme formülü

Bu formül aslında uygulamak kolaydır:

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

Şimdi, tek sorun, formülün sadece olumlu olması n. Kullanmaya çalışırsanız n = 0, formül yanlış verir 0. Bununla birlikte, bu kolayca sabitlenir: Girdiye boole olumsuzlama uygulayarak ve bunu formülün çıktısına ekleyerek, negatif olmayan tüm kullanıcılar için doğru çıktı verilir n. Böylece, bu düzeltmeli program:

;!╠@/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

Benim için olumsuz cevaplar veriyor ...
Leaky Nun

@LeakyNun Bu, hassasiyet limitleri nedeniyle. Büyük girişler için (etrafta n = 100), (-1)**n/n!çift ​​duyarlıklı IEEE 754 yüzmeleriyle gösterilemez Bu zorluğa göre kabul edilebilir.
Mego

Hatta n=4...
Leaky Nun

@LeakyNun Oh. Neden katlı bölüm kullandığımı bilmiyorum. Şimdi tamir ediyorum.
Mego



0

Alice , 20 18 bayt

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

Çevrimiçi deneyin!

açıklama

Bu kullanımlar gelen tekrarlama Laikoni cevabı , ! N = n! (N-1) + (-1) n . Funciton cevabına benzer şekilde, temel durumu kullanıyorum ! (- 1) = 1 . Bunu 1'i yığına koyduk 1.. Sonra bu...

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

... sadece olağan ondalık giriş / çıkış çerçevesidir. Ana kod aslında

&wq*eqE+]k

Bozuldu:

&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.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.