W subfactorial lub rencontres numery ( A000166 ) są sekwencje o numerach podobnych do silni liczb, które pojawiają się w kombinatoryki permutacji. W szczególności n th subfactorial ! N daje liczbę zaburzeniami z zestawem n elementów. Wykolejenie to permutacja, w której żaden element nie pozostaje w tej samej pozycji. Podfaktor można zdefiniować za pomocą następującej relacji powtarzalności:
!n = (n-1) (!(n-1) + !(n-2))
W rzeczywistości ta sama relacja powtarzalności obowiązuje dla silni, ale dla podfrakcji zaczynamy od:
!0 = 1
!1 = 0
(Dla silni mielibyśmy oczywiście 1! = 1 ).
Twoim zadaniem jest obliczenie ! N , biorąc pod uwagę n .
Zasady
Podobnie jak silnia, podfaktor rośnie bardzo szybko. W porządku, jeśli twój program może obsługiwać tylko takie dane wejściowe n , że ! N może być reprezentowany przez rodzimy typ liczbowy twojego języka. Jednak twój algorytm musi teoretycznie działać dla dowolnego n . Oznacza to, że możesz założyć, że wyniki całkowite i wartość pośrednia mogą być reprezentowane dokładnie przez Twój język. Zauważ, że wyklucza to stałą e, jeśli jest przechowywana lub obliczana ze skończoną precyzją.
Wynik musi być dokładną liczbą całkowitą (w szczególności nie można przybliżać wyniku za pomocą notacji naukowej).
Możesz napisać program lub funkcję i użyć dowolnej ze standardowych metod odbierania danych wejściowych i dostarczania danych wyjściowych.
Możesz używać dowolnego języka programowania , ale pamiętaj, że te luki są domyślnie zabronione.
To jest golf golfowy , więc wygrywa najkrótsza ważna odpowiedź - mierzona w bajtach .
Przypadki testowe
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
źródło
Odpowiedzi:
Funciton , 336 bajtów
Liczba bajtów zakłada kodowanie UTF-16 za pomocą BOM.
Definiuje to funkcję,
f
która przyjmuje jedną liczbę całkowitą i wysyła inną liczbę całkowitą przy skręcie o 90 stopni w lewo. Działa dla dowolnie dużych nakładów.Wypróbuj online!
Biorąc pod uwagę, że jest to Funciton, jest nawet dość szybki (n = 20 zajmuje około 14 sekund na TIO). Główne spowolnienie wynika z podwójnej rekurencji, ponieważ nie sądzę, że interpreter Funciton automatycznie zapamiętuje funkcje.
Niestety, niektóre czcionki o stałej szerokości nie mają prawidłowej szerokości
♭
i / lub wstawiają małe odstępy między wierszami. Oto zrzut ekranu kodu z TIO w całej krasie:Wydaje mi się, że można jeszcze trochę zagrać w golfa, np. Zmieniając warunek z
>0
na<1
i zamieniając gałęzie warunkowe, abym mógł ponownie użyć literału liczb, lub może używając zupełnie innej formuły, ale jestem całkiem zadowolony z tego, jak kompaktowy jest już.Wyjaśnienie
To w zasadzie implementuje rekurencję podaną w wyzwaniu, chociaż wykorzystuje podstawowy przypadek ! (- 1) =! 0 = 1 . n-1 i n-2 są obliczane z funkcją poprzednika
♭
, a wynik pośredni n-1 jest ponownie wykorzystywany w trzech miejscach. Nie ma o wiele więcej, więc po prostu szybko przejdę przez kontrolę:Jest to nagłówek funkcji, która emituje wejściowe z funkcji n długo dołączony linii. To natychmiast dochodzi do trójnika, który po prostu powiela wartość.
0
Box jest tylko dosłowne numeryczny. Łącznik 4-kierunkowy oblicza dwie funkcje: ścieżka prowadząca od dołu oblicza 0 <n , której użyjemy do określenia przypadku podstawowego. Ścieżka prowadząca osobno w lewo oblicza 0 << n (przesunięcie w lewo), ale tę wartość odrzucamy wraz z konstrukcją Starkowa .Wprowadzamy to do trójstronnej warunkowej
?
. Jeśli wartość jest fałszywa, zwracamy stały wynik1
. Luźny koniec po prawej stronie?
jest wyjściem funkcji. Obracam go tutaj o 180 stopni, aby względna orientacja wejścia i wyjściaf
była wygodniejsza w pozostałej części programu.Jeśli warunek był spełniony, zostanie użyta inna wartość. Spójrzmy na ścieżkę prowadzącą do tej gałęzi. (Zauważ, że ocena Funcitona jest w rzeczywistości leniwa, więc ta gałąź nigdy nie będzie oceniana, jeśli nie będzie potrzebna, co umożliwia w pierwszej kolejności rekurencję).
W drugiej gałęzi najpierw obliczamy n-1, a następnie dwukrotnie dzielimy ścieżkę, aby otrzymać trzy kopie wartości (jedna dla współczynnika nawrotu, jedna dla pierwszego podfaktora, ostatnia dla n-2 ).
Jak powiedziałem, ponownie zmniejszamy jedną kopię drugą
♭
, a następnie rekurencyjnie podajemy zarówno n-1, jak i n-2f
i ostatecznie dodajemy oba wyniki razem do pliku+
.Pozostało nam pomnożyć n-1 przez ! (N-1) +! (N-2) .
źródło
Oaza , 5 bajtów
Korzysta ze wzoru podanego przez Martina. Kod:
Wersja przekrojowa:
z
a(0) = 1
ia(1) = 0
.Objaśnienie
a(n) =
:Wypróbuj online!
źródło
X
:-) BTW, czy wdrożenie tego jeszcze? Któregoś dnia nie będziemy w stanie uciec od zmiany początkowych wartościHaskell , 25 bajtów
Wypróbuj online! Używa drugiej wznowienia ze strony OEIS .
źródło
Galaretka , 7 bajtów
To podejście konstruuje odstępstwa, więc jest raczej powolne.
Wypróbuj online!
Jak to działa
źródło
Brachylog (2), 11 bajtów
Wypróbuj online!
Wyjaśnienie
Jest to w zasadzie tylko bezpośrednie tłumaczenie specyfikacji z angielskiego na Brachylog (a zatem ma tę zaletę, że można ją łatwo zmodyfikować w celu obsługi niewielkich zmian w specyfikacji, takich jak znalezienie liczby odchyleń konkretnej listy).
źródło
Języki z wbudowanymi rozwiązaniami
Zgodnie z sugestią xnora jest to odpowiedź CW, w której należy edytować trywialne rozwiązania oparte na jednym wbudowanym narzędziu do obliczania podfrakcji lub wygenerowania wszystkich derangencji.
Mathematica, 12 bajtów
źródło
Python 3 ,
3532 bajtówWykorzystuje to relację powtarzalności ! N = n! (N-1) + (-1) n z odpowiedzi Haskell @ Laikoni , z przypadkiem podstawowym ! 0 = 1 .
Wypróbuj online!
źródło
f=lambda n:n<1or n*f(n-1)+(-1)**n
.n=-1
, nie ma znaczenia, jakiej wartości użyjesz. Może to być przydatne w niektórych językach (np. W Mathematica można pozostawić go niezdefiniowanym, jeśli pozwoli to zaoszczędzić bajty).M , 9 bajtów
Jak widać po usunięciu
Ḟ
, M używa matematyki symbolicznej, więc nie będzie problemów z precyzją.Wypróbuj online! Nie najkrótsze opublikowane rozwiązanie, ale szybkie .
Jak to działa
źródło
MATL ,
98 bajtówPodobnie jak w przypadku odpowiedzi Jelly @Dennis , tak naprawdę buduje permutacje i liczy, ile z nich to odstępstwa; więc jest wolny.
Wypróbuj online!
źródło
Matematyka , 21 bajtów
Jestem bardzo nowy i nie mam pojęcia, co robię ...
Wypróbuj online!
źródło
Round[(#/. 0->2)!/E]&
i±0=1;±n_:=Round[n!/E]
(chociaż nie wiem, czy Mathics obsługuje kodowanie jednobajtowe plików źródłowych, jak robi to Mathematica).±
drugiego. Działa zf
, ale kosztem dwóch bajtów.Round[#!/E]+1-Sign@#&
. Irytujące wartości początkowe ...!Rubinowy, 27 bajtów
~0**n
jest krótszy niż(-1)**n
!źródło
CJam (10 bajtów)
Demo online .
Wykorzystuje to nawrót
!n = n !(n-1) + (-1)^n
, z której zacząłem,n! / e
a następnie odkryłem, że był już w OEIS.Sekcja
Pętla oblicza
(-1)^n !n
, dlatego na końcu musimy przyjąć wartość bezwzględną:źródło
05AB1E , 8 bajtów
Wypróbuj online!
Wyjaśnienie
źródło
MATLAB, 33 bajty
Funkcja anonimowa, która korzysta ze wzoru z Rozdziału 3 Derangements i aplikacji Mehdi Hassani.
Przykładowe zastosowanie:
źródło
JavaScript (ES6), 26 bajtów
Wykorzystuje relację powtarzalności z odpowiedzi @ Laikoni. W ES7 możesz zapisać bajt, używając
+(-1)**n
zamiast-(~n%2|1)
.źródło
PostScript,
817669 bajtówOto implementacje obu formuł.
n * f (n-1) + (- 1) ^ n
/ f {dup 0 eq {pop 1} {dup dup 1 sub f mul Exchange 2 mod 2 mul 1 sub sub} ifelse} defTa wersja generuje liczbę zmiennoprzecinkową. Jeśli konieczne jest wyprowadzenie liczby całkowitej:
który waży 73 bajty.
Druga formuła jest nieco dłuższa: 81 bajtów.
(n-1) * (f (n-1) + f (n-2))
Funkcje te pobierają argument ze stosu i pozostawiają wynik na stosie.
Możesz przetestować funkcje w pliku lub w interaktywnym monitie PostScript (np. GhostScript) za pomocą
wydajność
Oto kompletny plik PostScript, który renderuje dane wyjściowe na ekran lub stronę drukarki. (Komentarze w PostScript zaczynają się od
%
).źródło
-1 3 2 roll exp
jest nieco krótszy niżexch 2 mod 2 mul 1 sub
.exp
: oops: Zwraca jednak liczbę zmiennoprzecinkową i myślę, że muszę podać liczbę całkowitą, aby była zgodna z pytaniem.cvi
i zaoszczędzić. (Uwaga: nieprzetestowane, ale po przeczytaniu dokumentu myślę, że powinien działać).cvi
działa i wciąż jest krótszy niż moja poprzednia wersja.PHP, 69 bajtów
użyj tego sposobu
a(n) = n*a(n-1) + (-1)^n
źródło
PHP,
5044Biegnij z
echo <n> | php -nR '<code>
Piękno
a(n) = n*a(n-1) + (-1)^n
polega na tym, że zależy to tylko od poprzedniej wartości. Pozwala to na iteracyjne zamiast rekurencyjne. To oszczędza długą deklarację funkcji .-6 bajtów przez @Titus. Dzięki !
źródło
$i++<$argv[1]
. -2 bajtów:for(;$i++<$argv[1];)$n=++$n*$i-$i%2*2;echo$n+1;
. (-3 bajty z-R
i$argn
.)-R
i$argn
?Mathematica, 40 bajtów
Który ma 31 bajtów przy domyślnym kodowaniu ISO 8859-1.
źródło
C, 34 bajty
Wyjaśnienie:
źródło
R, 47 bajtów
Używa tej samej formuły, co odpowiedź Mego .
Metoda alternatywna, 52 bajty przy użyciu
PerMallows
bibliotekiźródło
Właściwie 18 bajtów
Wypróbuj online!
Wyjaśnienie:
Wersja 12-bajtowa, która działałaby, gdyby faktycznie miała większą precyzję:
Wypróbuj online!
W przeciwieństwie do wszystkich innych odpowiedzi (od momentu opublikowania), to rozwiązanie nie używa ani formuły rekurencyjnej, ani formuły sumowania. Zamiast tego używa następującej formuły:
Ta formuła jest stosunkowo łatwa do wdrożenia w rzeczywistości:
Jedyny problem polega na tym, że formuła ma tylko wartość dodatnią
n
. Jeśli spróbujesz użyćn = 0
, formuła niepoprawnie się wyda0
. Można to jednak łatwo naprawić: poprzez zastosowanie negacji logicznej na wejściu i dodanie jej do wyniku formuły, poprawne dane wyjściowe są podawane dla wszystkich nieujemnychn
. Zatem program z tą korektą to:źródło
n = 100
)(-1)**n/n!
nie można ich przedstawić za pomocą pływaków o podwójnej precyzji IEEE 754. To jest do przyjęcia w zależności od wyzwania.n=4
...Skumulowane , 30 bajtów
Wypróbuj online!
Prosta funkcja rekurencyjna. Wykorzystuje fakt, że
!n = not n
dlan < 2
. Jak zadzwonićn f
.źródło
Alice ,
2018 bajtówWypróbuj online!
Wyjaśnienie
Wykorzystuje rekursja z Laikoni na odpowiedź , ! N = N + (n-1) + (-1) n . Podobnie jak odpowiedź Funcitona, używam podstawowego przypadku ! (- 1) = 1 . Kładziemy 1 na stosie
1.
. Wtedy to...... to zwykła platforma dziesiętna we / wy. Główny kod jest w rzeczywistości
Zepsuty:
źródło