Problema de Josefo (contando)


29

El reto

Escriba una función que tome dos enteros positivos n y k como argumentos y devuelva el número de la última persona que queda fuera de n después de contar cada k -ésima persona.

Este es un desafío de código de golf, por lo que gana el código más corto.

El problema

n personas (numeradas del 1 al n ) están paradas en un círculo y cada k -ésima se cuenta hasta que quede una sola persona (consulte el artículo correspondiente de wikipedia ). Determine el número de esta última persona.

Por ejemplo, para k = 3 dos personas serán omitidas y la tercera será descontada. Es decir, para n = 7, los números se contarán en el orden 3 6 2 7 5 1 (en detalle 1 2 3 4 5 6 7 1 2 4 5 7 1 4 5 1 4 1 4 ) y, por lo tanto, la respuesta es 4 .

Ejemplos

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

Respuestas:


5

GolfScript, 17 bytes

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

Toma n kla pila y deja el resultado en la pila.

Disección

Esto usa la recurrencia g(n,k) = (g(n-1,k) + k) % ncon g(1, k) = 0(como se describe en el artículo de Wikipedia) con la recursión reemplazada por un pliegue.

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

¿Puedes agregar una explicación, por favor?
Sherlock9

@ Sherlock9, logré entender lo que estaba haciendo a pesar de que habían pasado casi 3.5 años. ¿Quién dice que GolfScript es de solo lectura? ;)
Peter Taylor

Ejem. s / leer / escribir /
Peter Taylor

Lo siento. Hace solo dos o tres días que empecé a aprender Golfscript y cada vez que leía tu código, pensaba que me había perdido algo. ... Ok, todavía estoy perdiendo algo, ¿cómo plegar {k block}sobre [0..n-1]conseguir que g(0,k) 0 kpara empezar? Lo siento, si estoy publicando estas preguntas en el lugar equivocado.
Sherlock9

@ Sherlock9, fold funciona en parejas, por lo que lo primero que hace es evaluar 0 1 block. Muy convenientemente, eso pasa a ser g(1, k) (2-1) block. Entonces comienza en g(1,k) 1lugar de hacerlo g(0,k) 0. Luego, después de ejecutar el bloque, empuja el siguiente elemento de la matriz ( 2) y ejecuta el bloque nuevamente, etc.
Peter Taylor

14

Máquina de registro Minsky (25 estados sin interrupción)

Técnicamente no es una función, pero está en un paradigma informático que no tiene funciones per se ...

Esta es una ligera variación en el caso de prueba principal de mi primer desafío de interpretación MRM : Problema de Josephus como máquina de registro Minsky

Entrada en registros ny k; salida en el registro r; se supone que r=i=t=0a la entrada. Las dos primeras instrucciones de detención son casos de error.


Creo que tienes que ajustar tu máquina ligeramente. Si lo leí correctamente, la salida está indexada a cero, ¿no?
Howard

Estaba pensando en la otra dirección: si k=1entonces r=0. Hmm, tengo que pensar en esto otra vez ...
Howard

Mientras leo su diagrama, isimplemente está contando de 2a nmientras que res el registro que acumula el resultado.
Howard

@Howard, busqué los comentarios que hice cuando escribí esto por primera vez y tienes razón. Whoops Ahora corregido (creo - probará más a fondo más tarde).
Peter Taylor

7

Python, 36

También usé la fórmula de wikipedia:

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

Ejemplos:

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

6

Mathematica, 38 36 bytes

La misma fórmula de 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 caracteres

Esta es prácticamente la fórmula que ofrece el artículo de Wikipedia vinculado anteriormente:

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

Para variar, aquí hay una implementación que realmente ejecuta la simulación (99 caracteres):

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

44
Guardar un personaje: j(n,k){return--n?(j(n,k)+k-1)%-~n+1:1;}.
Ugoren

5

dc, 27 bytes

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

Utiliza la recurrencia del artículo de Wikipedia. Explicación:

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

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

Ejecuta la simulación.

Alternativamente, usando la fórmula (31 caracteres):

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

Espero que a Howard no le importe que haya ajustado ligeramente el formato de entrada para adaptarlo a un verbo diádico en J.

Uso:

   7 j 3
4
   123 j 12
21

4

GolfScript, 32 24 bytes

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

Uso: espera que los dos parámetros n y k estén en la pila y deja el valor de salida.

(gracias a Peter Taylor por sugerir un enfoque iterativo y muchos otros consejos)

El viejo enfoque (recursivo) de 32 caracteres:

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

Este es mi primer GolfScript, así que háganme saber sus críticas.


1
1-tiene un código de operación especial (. Del mismo modo 1+es ). No tiene que usar caracteres alfabéticos para el almacenamiento, por lo que podría usar, por ejemplo, en ^lugar de Jy no necesitar un espacio después. Tiene mucho más tiempo $de lo habitual en un programa bien desarrollado: considere si puede reducirlos usando alguna combinación de \@..
Peter Taylor

@PeterTaylor ¡Muchas gracias por estos excelentes consejos! Es bastante difícil comprender todos los operadores de Golfscript y pasé por alto estos dos muy sencillos. Solo aplicando las dos primeras sugerencias logré acortar el código en 5 caracteres. También intentaré eliminar las $referencias.
Cristian Lupascu

1
Además, la recursividad no es realmente cosa de GolfScript. Intenta darle la vuelta y hacer un bucle. Puedo reducirlo a 19 caracteres (aunque el código no probado) de esa manera. Sugerencia: desenrolle la función gdel artículo de Wikipedia, y use ,y /.
Peter Taylor

1
{,{\2$+\)%}*)\;}:f;Asegúrese de entender por qué funciona;)
Peter Taylor

1
Un último truco: en lugar de usar 2 caracteres para acceder kdentro del bucle y luego 2 más para descartarlo al final, podemos tirar hacia adentro usando +hasta 17 caracteres: {{@+\)%}+\,*)}:f;dudo que eso pueda mejorarse.
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

Hace la simulación real. Demostración:

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 caracteres

Hace la simulación, no calcula la fórmula.
Mucho más largo que la fórmula, pero más corto que la otra simulación 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;
}

Notas:
1. Asigna memoria y nunca libera.
2. Asigna en n*8lugar de n*4, porque yo uso p[n]. Podría asignar (n+1)*4, pero son más personajes.


1

C ++, 166 bytes

Golfizado:

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

Sin golf:

#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
Puede guardar bytes en la Jfunción, utilizando el operador ternario.
Yytsi

intnen tu versión de golf no compilará
Felipe Nardi Batista

puedes quitar espacio en#include <list>
Felipe Nardi Batista

1

J, 8 bytes

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
¿No se supone que debe tomar dos entradas?
Erik the Outgolfer


1

Q, 34 bytes

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


0

Haskell, 29

Usando la fórmula de wikipedia.

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

0

JavaScript (ECMAScript 5), 48 bytes

Usando ECMAScript 5 ya que esa era la última versión de JavaScript en el momento en que se hizo esta pregunta.

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

Versión ES6 (no competitiva), 33 bytes

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

Explicación

No hay mucho que decir aquí. Solo estoy implementando la función que me da el artículo de Wikipedia.


0

05AB1E , 11 bytes

L[Dg#²<FÀ}¦

Pruébalo en línea!

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

8vo , 82 bytes

Código

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

SED (diagrama de efecto de pila) es:n k -- m

Uso y explicación

El algoritmo usa una matriz de enteros como este: si el valor de las personas es 5, entonces la matriz será [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 bytes

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

Pruébalo en línea!

Un enfoque iterativo basado en la solución de programación dinámica.

Explicación

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 bytes

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

Pruébalo en línea!

Cómo funciona

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 bytes

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

Pruébalo en línea!

Un byte podría salvarse mediante la indexación 0 k , pero en realidad no es un índice, así que decidí no hacerlo.

Explicación:

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

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

¡Importante! El guión se llama a sí mismo de forma recursiva. Así que guarda el guión comof.ps1 archivo en el directorio actual. También puede llamar a una variable de bloque de script en lugar de un archivo de script (consulte el script de prueba a continuación). Eso llama tiene la misma longitud.

Script de prueba:

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

Salida:

True: 7
True: 7
True: 4
True: 1
True: 1
True: 21
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.