Problem z Józefem (odliczanie)

29

Wyzwanie

Napisz funkcję, która przyjmuje dwie dodatnie liczby całkowite n i k jako argumenty i zwraca liczbę ostatnich osób pozostających poza n po odliczeniu każdego k tej osoby.

To wyzwanie dla golfa, więc wygrywa najkrótszy kod.

Problem

n osób (ponumerowanych od 1 do n ) stoi w kręgu i każdy k- ty jest odliczany, aż pozostanie jedna osoba (patrz odpowiedni artykuł na Wikipedii ). Określ liczbę tej ostatniej osoby.

Np. Dla k = 3 dwie osoby zostaną pominięte, a trzecia zostanie odliczona. Tj. Dla n = 7 liczby będą odliczane w kolejności 3 6 2 7 5 1 (szczegółowo 1 2 3 4 5 6 7 1 2 4 5 7 1 4 5 1 4 1 4 ), a zatem odpowiedź wynosi 4 .

Przykłady

J(7,1) = 7      // people are counted out in order 1 2 3 4 5 6 [7]
J(7,2) = 7      // people are counted out in order 2 4 6 1 5 3 [7]
J(7,3) = 4      // see above
J(7,11) = 1
J(77,8) = 1
J(123,12) = 21
Howard
źródło

Odpowiedzi:

5

GolfScript, 17 bajtów

{{@+\)%}+\,*)}:f;

Bierze n kna stos i pozostawia wynik na stosie.

Sekcja

Wykorzystuje to powtórzenie g(n,k) = (g(n-1,k) + k) % nz g(1, k) = 0(jak opisano w artykule na Wikipedii) z rekurencją zastąpioną przez fold.

{          # Function declaration
           # Stack: n k
  {        # Stack: g(i-1,k) i-1 k
    @+\)%  # Stack: g(i,k)
  }+       # Add, giving stack: n {k block}
  \,*      # Fold {k block} over [0 1 ... n-1]
  )        # Increment to move from 0-based to 1-based indexing
}:f;
Peter Taylor
źródło
Czy możesz dodać wyjaśnienie?
Sherlock9,
@ Sherlock9, udało mi się dowiedzieć, co robię, pomimo upływu prawie 3,5 roku. Kto powiedział, że GolfScript jest tylko do odczytu? ;)
Peter Taylor
Ahem. s / read / write /
Peter Taylor
Przepraszam. Naukę gry w golfa zacząłem dopiero dwa lub trzy dni temu i za każdym razem, gdy czytam twój kod, ciągle myślę, że coś przeoczyłem. ... Ok, ja wciąż czegoś brakuje, w jaki sposób składane {k block}przez [0..n-1]Ci g(0,k) 0 kzacząć? Przepraszam, jeśli zamieszczam te pytania w niewłaściwym miejscu.
Sherlock9,
@ Sherlock9, fold działa parami, więc pierwszą rzeczą jest ocena 0 1 block. Bardzo wygodnie to się dzieje g(1, k) (2-1) block. Więc zaczyna się g(1,k) 1raczej niż g(0,k) 0. Następnie po wykonaniu bloku wypycha następny element z tablicy ( 2) i wykonuje blok ponownie itp.
Peter Taylor,
14

Maszyna rejestru Minsky'ego (25 stanów bez zatrzymania)

Nie jest to technicznie funkcja, ale jest w paradygmacie obliczeniowym, który sam w sobie nie ma funkcji ...

Jest to niewielka zmiana w głównym przypadku testowym mojego pierwszego wyzwania interpretacyjnego MRM : Josephus problem as Minsky register machine

Wprowadzanie do rejestrów ni k; wyjście w rejestrze r; zakłada się, że r=i=t=0przy wejściu. Pierwsze dwie instrukcje zatrzymania to przypadki błędów.

Peter Taylor
źródło
Myślę, że musisz lekko wyregulować maszynę. Jeśli poprawnie go odczytam, wynik jest indeksowany na zero, prawda?
Howard
Myślałem w drugą stronę: jeśli k=1tak r=0. Hmm, muszę jeszcze raz o tym pomyśleć ...
Howard
Jak czytam swój schemat, ijest po prostu licząc od 2celu n, gdy rjest rejestrem, który gromadzi się na wynik.
Howard
@Howard, przejrzałem komentarze, które napisałem, kiedy pierwszy raz to napisałem i masz rację. Ups Teraz poprawione (wierzę - dokładniej przetestuje później).
Peter Taylor
7

Python, 36

Użyłem również formuły z wikipedii:

J=lambda n,k:n<2or(J(n-1,k)+k-1)%n+1

Przykłady:

>>> J(7,3)
4
>>> J(77,8)
1
>>> J(123,12)
21
grc
źródło
6

Mathematica, 38 36 bajtów

Ta sama formuła Wikipedii:

1~f~_=1
n_~f~k_:=Mod[f[n-1,k]+k,n,1]
Mr.Wizard
źródło
1
If[#<2,1,Mod[#0[#-1,#2]+#2,#,1]]&
alephalpha
5

C, 40 znaków

Jest to właściwie tylko formuła, którą podaje powyższy link w Wikipedii:

j(n,k){return n>1?(j(n-1,k)+k-1)%n+1:1;}

Dla odmiany, oto implementacja, która faktycznie uruchamia symulację (99 znaków):

j(n,k,c,i,r){char o[999];memset(o,1,n);for(c=k,i=0;r;++i)(c-=o[i%=n])||(o[i]=!r--,c=k);
return i;}
chlebak
źródło
4
Zapisz znak: j(n,k){return--n?(j(n,k)+k-1)%-~n+1:1;}.
ugoren
5

dc, 27 bajtów

[d1-d1<glk+r%1+]dsg?1-skrxp

Wykorzystuje wznowienie z artykułu z Wikipedii. Wyjaśnienie:

# comment shows what is on the stack and any other effect the instructions have
[   # n
d   # n, n
1-  # n-1, n
d   # n-1, n-1, n
1<g # g(n-1), n ; g is executed only if n > 1, conveniently g(1) = 1
lk+ # g(n-1)+(k-1), n; remember, k register holds k-1
r%  # g(n-1)+(k-1) mod n
1+  # (g(n-1)+(k-1) mod n)+1
]
dsg # code for g; code also stored in g
?   # read user input => k, n, code for g
1-  # k-1, n, code for g
sk  # n, code for g; k-1 stored in register k
r   # code for g, n
x   # g(n)
p   # prints g(n)
Geoff Reedy
źródło
4

J, 45 znaków

j=.[:{.@{:]([:}.]|.~<:@[|~#@])^:(<:@#)>:@i.@[

Uruchamia symulację.

Alternatywnie, korzystając ze wzoru (31 znaków):

j=.1:`(1+[|1-~]+<:@[$:])@.(1<[)

Mam nadzieję, że Howardowi nie przeszkadza, że ​​nieznacznie dostosowałem format wejściowy, aby pasował do czasownika dyadycznego w J.

Stosowanie:

   7 j 3
4
   123 j 12
21
Gareth
źródło
4

GolfScript, 32 24 bajty

:k;0:^;(,{))^k+\%:^;}/^)

Zastosowanie: Oczekuje, że dwa parametry n i k znajdą się na stosie i pozostawia wartość wyjściową.

(podziękowania dla Petera Taylora za zasugerowanie iteracyjnego podejścia i wiele innych wskazówek)

Stare (rekurencyjne) podejście 32 znaków:

{1$1>{1$(1$^1$(+2$%)}1if@@;;}:^;

To jest mój pierwszy GolfScript, więc daj mi znać, co krytykujesz.

Cristian Lupascu
źródło
1
1-ma specjalny kod operacyjny (. Podobnie 1+jest ). Nie musisz używać znaków alfabetu do przechowywania, więc możesz użyć np. ^Zamiast Ji nie potrzebujesz po nim spacji. Masz znacznie więcej $niż zwykle w dobrze golfowym programie: zastanów się, czy możesz je zmniejszyć za pomocą kombinacji \@..
Peter Taylor
@PeterTaylor Wielkie dzięki za te wspaniałe wskazówki! Trudno jest pojąć wszystkich operatorów Golfscript i przeoczyłem te dwa bardzo proste. Tylko stosując pierwsze dwie sugestie udaje mi się skrócić kod o 5 znaków. Spróbuję również usunąć $odniesienia.
Cristian Lupascu
1
Ponadto rekurencja tak naprawdę nie jest rzeczą GolfScript. Spróbuj go obrócić i zrobić pętlę. W ten sposób mogę sprowadzić go do 19 znaków (choć nie przetestowałem kodu). Wskazówka: rozwiń funkcję gz artykułu z Wikipedii oraz użyj ,i /.
Peter Taylor
1
{,{\2$+\)%}*)\;}:f;Upewnij się, że rozumiesz, dlaczego to działa;)
Peter Taylor
1
Ostatnia sztuczka: zamiast używać 2 znaków, aby uzyskać dostęp kdo pętli, a następnie 2 więcej, aby odrzucić ją na końcu, możemy wciągnąć ją do środka za pomocą, +aby uzyskać do 17 znaków: {{@+\)%}+\,*)}:f;Wątpię, że można to poprawić.
Peter Taylor
3

Groovy, 36 bajtów

def j(n,k){n>1?(j(n-1,k)+k-1)%n+1:1}
Książę John Wesley
źródło
2

Haskell, 68

j n=q$cycle[0..n]
q l@(i:h:_)k|h/=i=q(drop(k-1)$filter(/=i)l)k|1>0=i

Czy rzeczywista symulacja. Demonstracja:

GHCi> j 7 1
7
GHCi> j 7 2
7
GHCi> j 7 3
4
GHCi> j 7 11
1
GHCi> j 77 8
1
GHCi> j 123 12
21

przestał się obracać w lewo
źródło
2

Scala, 53 bajty

def?(n:Int,k:Int):Int=if(n<2)1 else(?(n-1,k)+k-1)%n+1
Książę John Wesley
źródło
1

C, 88 znaków

Wykonuje symulację, nie oblicza wzoru.
Znacznie dłużej niż formuła, ale krócej niż inne symulacje C.

j(n,k){
    int i=0,c=k,r=n,*p=calloc(n,8);
    for(;p[i=i%n+1]||--c?1:--r?p[i]=c=k:0;);
    return i;
}

Uwagi:
1. Przydziela pamięć i nigdy nie zwalnia.
2. Przydziela n*8zamiast n*4, ponieważ używam p[n]. Można przydzielić (n+1)*4, ale to więcej znaków.

ugoren
źródło
1

C ++, 166 bajtów

Gra w golfa:

#include<iostream>
#include <list>
int j(int n,int k){if(n>1){return(j(n-1,k)+k-1)%n+1;}else{return 1;}}
int main(){intn,k;std::cin>>n>>k;std::cout<<j(n,k);return 0;}

Nie golfowany:

#include<iostream>
#include <list>
int j(int n,int k){
    if (n > 1){
        return (j(n-1,k)+k-1)%n+1;
    } else {
        return 1;
    }
}
int main()
{
    int n, k;
    std::cin>>n>>k;
    std::cout<<j(n,k);
    return 0;
}
Michelfrancis Bustillos
źródło
2
Możesz zapisać bajty w Jfunkcji, używając operatora trójskładnikowego.
Yytsi
intnw twojej wersji golfowej nie da się skompilować
Felipe Nardi Batista
możesz usunąć miejsce w#include <list>
Felipe Nardi Batista
1

J, 8 bajtów

1&|.&.#:

       1&|.&.#: 10
    5

       1&|.&.#: 69
    11

        1&|.&.#: 123456
    115841

        1&|.&.#: 123245678901234567890x NB. x keeps input integral
    98917405212792722853

All credit to Roger Hui, co-inventor of J and all-round uber-genius
www.jsoftware.com for free j software across many platforms

Explanation
    (J works right-to-left)
     #:       convert input to binary
     &.       a&.b <=> perform b, perform a, perform reverse of b
     1&|.     rotate bitwise one bit left

So
    1&|.&.#: 10

    a. #:            convert input (10) TO binary -> 1 0 1 0
    b. 1&|.          rotate result 1 bit left -> 0 1 0 1
    c. due to the &. perform convert FROM binary -> 5 (answer)
Richard Donovan
źródło
1
Czy nie powinno to zająć dwóch wejść?
Erik the Outgolfer,
1

Rubin, 39 bajtów

def J(n,k)
n<2?1:(J(n-1,k)+k-1)%n+1
end

Wersja uruchomiona z przypadkami testowymi: http://ideone.com/pXOUc

Cristian Lupascu
źródło
1

Q, 34 bajty

f:{$[x=1;1;1+mod[;x]f[x-1;y]+y-1]}

Stosowanie:

q)f .'(7 1;7 2;7 3;7 11;77 8;123 12)
7 7 4 1 1 21
tartin
źródło
1

Rubinowy, 34 bajty

J=->n,k{n<2?1:(J(n-1,k)+k-1)%n+1}
Hauleth
źródło
0

Haskell, 29

Korzystanie z formuły z wikipedii.

1#_=1
n#k=mod((n-1)#k+k-1)n+1
alephalpha
źródło
0

JavaScript (ECMAScript 5), 48 bajtów

Korzystanie z ECMAScript 5, ponieważ była to najnowsza wersja JavaScript w momencie zadawania tego pytania.

function f(a,b){return a<2?1:(f(a-1,b)+b-1)%a+1}

Wersja ES6 (niekonkurująca), 33 bajty

f=(a,b)=>a<2?1:(f(a-1,b)+b-1)%a+1

Wyjaśnienie

Nie ma tu wiele do powiedzenia. Właśnie wdrażam funkcję, którą daje mi artykuł z Wikipedii.

Luke
źródło
0

05AB1E , 11 bajtów

L[Dg#²<FÀ}¦

Wypróbuj online!

L           # Range 1 .. n
 [Dg#       # Until the array has a length of 1:
     ²<F }  #   k - 1 times do:
        À   #     Rotate the array
          ¦ #   remove the first element
Riley
źródło
0

8 , 82 bajty

Kod

: j >r >r a:new ( a:push ) 1 r> loop ( r@ n:+ swap n:mod ) 0 a:reduce n:1+ rdrop ;

SED (diagram efektu stosu) to:n k -- m

Użycie i wyjaśnienie

Algorytm wykorzystuje tablicę liczb całkowitych takich jak ta: jeśli wartość ludzi wynosi 5, tablica będzie wynosić [1,2,3,4,5]

: j \ n k -- m
    >r                               \ save k
    >r a:new ( a:push ) 1 r> loop    \ make array[1:n]
    ( r@ n:+ swap n:mod ) 0 a:reduce \ translation of recursive formula with folding using an array with values ranging from 1 to n
    n:1+                             \ increment to move from 0-based to 1-based indexing
    rdrop                            \ clean r-stack
;

ok> 7 1 j . cr
7
ok> 7 2 j . cr
7
ok> 7 3 j . cr
4
ok> 7 11 j . cr
1
ok> 77 8 j . cr
1
ok> 123 12 j . cr
21
Dwór Chaosu
źródło
0

J , 24 bajty

1+1{1([:|/\+)/@,.1|.!.0#

Wypróbuj online!

Iteracyjne podejście oparte na rozwiązaniu do programowania dynamicznego.

Wyjaśnienie

1+1{1([:|/\+)/@,.1|.!.0#  Input: n (LHS), k (RHS)
                       #  Make n copies of k
                 1|.!.0   Shift left by 1 and fill with zero
    1          ,.         Interleave with 1
             /@           Reduce using
           +                Addition
        |/\                 Cumulative reduce using modulo
  1{                      Select value at index 1
1+                        Add 1
mile
źródło
0

J , 19 bajtów

1+(}:@|.^:({:@])i.)

Wypróbuj online!

Jak to działa

1+(}:@|.^:({:@])i.)   Left: k, Right: n
                i.    Generate [0..n-1]
        ^:            Repeat:
   }:@|.                Rotate left k items, and remove the last item
          ({:@])        n-1 (tail of [0..n-1]) times
1+                    Add one to make the result one-based
Bubbler
źródło
0

Japt , 15 bajtów

_é1-V Å}h[Uõ] Ì

Wypróbuj online!

Bajt może być zapisany przez 0-indeksowanie k , ale tak naprawdę nie jest to indeks, więc postanowiłem tego .

Wyjaśnienie:

         [Uõ]      :Starting with the array [1...n]
_      }h          :Repeat n-1 times:
 é1-V              : Rotate the array right 1-k times (i.e. rotate left k-1 times)
      Å            : Remove the new first element
              Ì    :Get the last value remaining
Kamil Drakari
źródło
0

PowerShell, 56 bajtów

param($n,$k)if($n-lt2){1}else{((.\f($n-1)$k)+$k-1)%$n+1}

Ważny! Skrypt wywołuje się rekurencyjnie. Zapisz skrypt jakof.ps1 plik w bieżącym katalogu. Możesz także wywołać zmienną blokową skryptu zamiast pliku skryptu (patrz skrypt testowy poniżej). Te połączenia mają tę samą długość.

Skrypt testowy:

$f = {

param($n,$k)if($n-lt2){1}else{((&$f($n-1)$k)+$k-1)%$n+1}

}

@(
    ,(7, 1, 7)
    ,(7, 2, 7)
    ,(7, 3, 4)
    ,(7, 11, 1)
    ,(77, 8, 1)
    ,(123,12, 21)
) | % {
    $n,$k,$expected = $_
    $result = &$f $n $k
    "$($result-eq$expected): $result"
}

Wydajność:

True: 7
True: 7
True: 4
True: 1
True: 1
True: 21
mazzy
źródło