Problema di Giuseppe Flavio (conto alla rovescia)


29

La sfida

Scrivi una funzione che prende due interi positivi n e k come argomenti e restituisce il numero dell'ultima persona rimasta da n dopo aver contato ogni k -esima persona.

Questa è una sfida di code-golf, quindi vince il codice più corto.

Il problema

n persone (numerate da 1 a n ) sono in piedi in un cerchio e ogni k -th viene contato fino a quando rimane una sola persona (vedi l' articolo di Wikipedia corrispondente ). Determina il numero di quest'ultima persona.

Ad esempio, per k = 3 verranno saltate due persone e il terzo verrà conteggiato. Vale a dire per n = 7 i numeri verranno conteggiati nell'ordine 3 6 2 7 5 1 (in dettaglio 1 2 3 4 5 6 7 1 2 4 5 7 1 4 5 1 4 1 4 ) e quindi la risposta è 4 .

Esempi

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

Risposte:


5

GolfScript, 17 byte

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

Prende n kin pila e lascia il risultato in pila.

Dissezione

Questo utilizza la ricorrenza g(n,k) = (g(n-1,k) + k) % ncon g(1, k) = 0(come descritto nell'articolo di Wikipedia) con la ricorsione sostituita da una piega.

{          # 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;

Puoi aggiungere una spiegazione, per favore?
Sherlock9,

@ Sherlock9, sono riuscito a capire cosa stavo facendo nonostante siano passati quasi 3,5 anni. Chi dice che GolfScript è di sola lettura? ;)
Peter Taylor,

Ahem. s / leggi / scrivi /
Peter Taylor,

Scusate. Ho iniziato a studiare Golfscript solo due o tre giorni fa e ogni volta che leggevo il tuo codice continuavo a pensare che mi mancava qualcosa. ... Ok, mi manca ancora qualcosa, come si fa piegare {k block}sopra [0..n-1]si ottiene g(0,k) 0 kper iniziare? Mi dispiace, se sto postando queste domande nel posto sbagliato.
Sherlock9,

@ Sherlock9, fold funziona a coppie, quindi la prima cosa che fa è valutare 0 1 block. Molto conveniente, sembra essere g(1, k) (2-1) block. Quindi inizia g(1,k) 1piuttosto che g(0,k) 0. Quindi, dopo aver eseguito il blocco, invia l'elemento successivo dall'array ( 2) ed esegue nuovamente il blocco, ecc.
Peter Taylor,

14

Minsky Register Machine (25 stati non-stop)

Tecnicamente non è una funzione, ma è in un paradigma informatico che non ha funzioni di per sé ...

Questa è una leggera variazione sul caso di test principale della mia prima sfida di interpretazione MRM : Problema di Josephus come macchina del registro Minsky

Inserimento nei registri ne k; uscita in registro r; si presume che r=i=t=0all'entrata. Le prime due istruzioni di arresto sono casi di errore.


Penso che devi regolare leggermente la tua macchina. Se l'ho letto correttamente l'output è indicizzato zero, non è vero?
Howard,

Stavo pensando dall'altra parte: se k=1allora r=0. Hmm, devo pensarci di nuovo ...
Howard,

Mentre leggo il tuo diagramma, ista semplicemente contando da 2a nmentre rè il registro che accumula il risultato.
Howard,

@Howard, ho cercato i commenti che ho fatto la prima volta che ho scritto questo e hai ragione. Ops. Ora corretto (credo - testerà più accuratamente in seguito).
Peter Taylor,

7

Python, 36

Ho anche usato la formula di Wikipedia:

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

Esempi:

>>> J(7,3)
4
>>> J(77,8)
1
>>> J(123,12)
21

6

Mathematica, 38 36 byte

Stessa formula di Wikipedia:

1~f~_=1
n_~f~k_:=Mod[f[n-1,k]+k,n,1]

1
If[#<2,1,Mod[#0[#-1,#2]+#2,#,1]]&
alephalpha,

5

C, 40 caratteri

Questa è praticamente solo la formula che l'articolo di Wikipedia sopra linkato dà:

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

Per varietà, ecco un'implementazione che esegue effettivamente la simulazione (99 caratteri):

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;}

4
Salvare un carattere: j(n,k){return--n?(j(n,k)+k-1)%-~n+1:1;}.
ugoren,

5

dc, 27 byte

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

Utilizza la ricorrenza dall'articolo di Wikipedia. Spiegazione:

# 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)

4

J, 45 caratteri

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

Esegue la simulazione.

In alternativa, usando la formula (31 caratteri):

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

Spero che a Howard non dispiaccia di aver leggermente modificato il formato di input per adattarlo a un verbo diadico in J.

Uso:

   7 j 3
4
   123 j 12
21

4

GolfScript, 32 24 byte

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

Utilizzo: si aspetta che i due parametri n e k siano nello stack e lascia il valore di output.

(grazie a Peter Taylor per aver suggerito un approccio iterativo e molti altri suggerimenti)

Il vecchio approccio (ricorsivo) di 32 caratteri:

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

Questo è il mio primo GolfScript, quindi per favore fatemi sapere le vostre critiche.


1
1-ha un codice operativo speciale (. Analogamente 1+è ). Non è necessario utilizzare i caratteri alfabetici per l'archiviazione, quindi è possibile utilizzare ad esempio ^invece di Je non è necessario uno spazio dopo di esso. Hai molti più messaggi $del solito in un programma ben studiato: considera se puoi ridurli usando una combinazione di \@..
Peter Taylor,

@PeterTaylor Grazie mille per questi ottimi consigli! È piuttosto difficile cogliere tutti gli operatori di Golfscript e ho trascurato questi due molto semplici. Solo applicando i primi due suggerimenti riesco ad accorciare il codice di 5 caratteri. Proverò anche a rimuovere i $riferimenti.
Cristian Lupascu,

1
Inoltre, la ricorsione non è proprio cosa di GolfScript. Prova a girarlo e fai un ciclo. Posso ottenere fino a 19 caratteri (anche se codice non testato) in quel modo. Suggerimento: srotolare la funzione gdall'articolo di Wikipedia e utilizzare ,e /.
Peter Taylor,

1
{,{\2$+\)%}*)\;}:f;Assicurati di capire perché funziona;)
Peter Taylor,

1
Un ultimo trucco: piuttosto che usare 2 personaggi per accedere kall'interno del loop e poi altri 2 per scartarlo alla fine, possiamo tirarlo dentro usando +per scendere fino a 17 caratteri: {{@+\)%}+\,*)}:f;dubito che possa essere migliorato.
Peter Taylor,



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

Fa la simulazione reale. Dimostrazione:

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



1

C, 88 caratteri

Fa la simulazione, non calcola la formula.
Molto più lungo della formula, ma più corto dell'altra simulazione 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;
}

Note:
1. Alloca memoria e non rilascia mai.
2. Alloca n*8invece di n*4, perché io uso p[n]. Potrebbe allocare (n+1)*4, ma sono più personaggi.


1

C ++, 166 byte

golfed:

#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;}

Ungolfed:

#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;
}

2
È possibile salvare byte sulla Jfunzione utilizzando l'operatore ternario.
Yytsi,

intnnella tua versione golfata non verrà compilato
Felipe Nardi Batista,

puoi rimuovere lo spazio in#include <list>
Felipe Nardi Batista

1

J, 8 byte

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)

1
Non dovrebbe prendere due input?
Erik the Outgolfer,


1

Q, 34 byte

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

Uso:

q)f .'(7 1;7 2;7 3;7 11;77 8;123 12)
7 7 4 1 1 21

1

Rubino, 34 byte

J=->n,k{n<2?1:(J(n-1,k)+k-1)%n+1}

0

Haskell, 29

Usando la formula da Wikipedia.

1#_=1
n#k=mod((n-1)#k+k-1)n+1

0

JavaScript (ECMAScript 5), 48 byte

Utilizzando ECMAScript 5 poiché quella era l'ultima versione di JavaScript al momento in cui è stata posta questa domanda.

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

Versione ES6 (non competitiva), 33 byte

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

Spiegazione

Non c'è molto da dire qui. Sto solo implementando la funzione che l'articolo di Wikipedia mi offre.


0

05AB1E , 11 byte

L[Dg#²<FÀ}¦

Provalo 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

0

8 ° , 82 byte

Codice

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

SED (Stack Effect Diagram) è:n k -- m

Uso e spiegazione

L'algoritmo utilizza un array di numeri interi come questo: se il valore di persone è 5, l'array sarà [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

0

J , 24 byte

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

Provalo online!

Un approccio iterativo basato sulla soluzione di programmazione dinamica.

Spiegazione

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

0

J , 19 byte

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

Provalo online!

Come funziona

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


0

Japt , 15 byte

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

Provalo online!

Un byte potrebbe essere salvato con l' indice 0 , ma in realtà non è un indice, quindi ho deciso di non farlo.

Spiegazione:

         [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


0

Powershell, 56 byte

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

Importante! Lo script si chiama ricorsivamente. Quindi salva lo script comef.ps1 file nella directory corrente. Inoltre è possibile chiamare una variabile di blocco di script anziché il file di script (vedere lo script di prova di seguito). Quella chiamata ha la stessa lunghezza.

Script di prova:

$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"
}

Produzione:

True: 7
True: 7
True: 4
True: 1
True: 1
True: 21
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.