Le dan una máquina con dos registros de 16 bits, x
y y
. Los registros se inicializan x=1
y y=0
. La única operación que puede hacer la máquina es el módulo de adición 65536. Es decir:
x+=y
-x
se sustituye por(x + y) mod 65536
;y
no ha cambiadoy+=x
- de manera similar paray
x+=x
-x
se sustituye por2x mod 65536
; legal solo six
es pary+=y
- de manera similar paray
El objetivo es obtener un número predeterminado en uno de los registros (ya sea x
o y
).
Escriba un programa o una subrutina que reciba un número (en stdin
, argv
parámetro de función, parte superior de la pila o cualquier otro lugar convencional) y genere un programa para obtener este número. La salida debe ir a stdout
, o (si su idioma no tiene stdout
) a cualquier otro dispositivo de salida convencional.
El programa de salida puede estar hasta el 100% más 2 pasos lejos de ser óptimo. Es decir, si el programa más corto para obtener el número objetivo tiene n
pasos, su solución no puede ser más larga que 2n+2
. Esta restricción es para evitar soluciones "demasiado fáciles" (por ejemplo, contar 1, 2, 3, ...) pero no requiere una optimización completa; Espero que el programa más corto sea más fácil de encontrar, pero no puedo estar seguro ...
Por ejemplo: Entrada = 25. Salida:
y+=x
x+=y
x+=y
x+=x
x+=x
x+=x
y+=x
Otro ejemplo: para cualquier número de Fibonacci, la salida tiene este patrón alterno. Para Entrada = 21, la salida es
y+=x
x+=y
y+=x
x+=y
y+=x
x+=y
y+=x
El código más corto (medido en bytes) gana.
(este rompecabezas se inspiró en un código para un procesador de 16 bits que tuve que generar recientemente)
PD: ¿para qué número es el programa óptimo más largo?
fuente
x+=x
legal solo six
es par? También para el programa más corto, creo que algo como BFS podría funcionar.x+=x
solo funciona para paresx
, ¿cómo es el ejemplo para una entrada de 25 dobles 3?Respuestas:
CJam, 31
Al igual que la respuesta de @Tobia , mi algoritmo también es
robadodescaradamente inspirado por la respuesta de @CChak . Pero, empuñando la magia negra que es CJam, logré hacer una implementación aún más pequeña del algoritmo.Pruébalo aquí.
Golfizado:
Sin golf:
Corríjame si me equivoco, pero creí que la operación del módulo 65536 utilizada en respuestas con un algoritmo similar es innecesaria. Interpreté la pregunta de tal manera que podemos suponer que la entrada será un número entero de 16 bits sin signo válido, y cualquier valor intermedio o resultado de este algoritmo también lo será.
fuente
Perl
10797Primer post, así que aquí va.
Que se ajusta a todos los criterios de adición de registros, pero no ejecuté una verificación exhaustiva para ver si mi respuesta siempre estuvo dentro de 2n + 2 del número óptimo de pasos. Sin embargo, está dentro del límite para cada número de Fibonacci.
Aquí hay un desglose más detallado
Como mencioné, este es mi primer intento de jugar al golf, así que estoy seguro de que esto se puede mejorar. Además, no estoy seguro de si la llamada de subrutina inicial debe contarse en una llamada recursiva o no, lo que podría hacernos subir algunos caracteres.
Curiosamente, podemos reducir el código en 11 bytes * y mejorar nuestra "eficiencia" en términos del número de operaciones de registro, relajando el requisito de que solo los valores pares pueden "duplicarse". Lo he incluido por diversión aquí:
Comience el apéndice:
Realmente me gustó este problema, y he estado jugando con él de vez en cuando durante las últimas dos semanas. Pensé que publicaría mis resultados.
Algunos numeros:
Usando un algoritmo BFS para encontrar una solución óptima, en los primeros 2 ^ 16 números solo hay 18 números que requieren 23 pasos. Ellos son: 58558, 59894, 60110, 61182, 61278, 62295, 62430, 62910, 63422, 63462, 63979, 64230, 64314, 4486, 64510, 64698, 64854, 65295.
Usando el algoritmo recursivo descrito anteriormente, el número "más difícil" de alcanzar es 65535, en 45 operaciones. (65534 toma 44, y hay 14 números que toman 43 pasos) 65535 es también la mayor desviación de óptimo, 45 vs 22. La diferencia de 23 pasos es 2n + 1. (Solo tres números llegan a 2n: 65534, 32767, 32751.) Exceptuando los casos triviales (paso cero), en el rango definido, el método recursivo promedia aproximadamente 1.4 veces la solución óptima.
En pocas palabras: para los números 1-2 ^ 16, el algoritmo recursivo nunca cruza el umbral definido de 2n + 2, por lo que la respuesta es válida. Sin embargo, sospecho que comenzaría a alejarse demasiado de la solución óptima para registros más grandes / más bits.
El código que utilicé para crear el BFS era descuidado, requiere mucha memoria, no estaba comentado y, deliberadamente, no estaba incluido. Entonces ... no tienes que confiar en mis resultados, pero estoy bastante seguro de ellos.
fuente
Python 3, 202 bytes
(Gracias a @rationalis por unos pocos bytes)
Aquí hay una solución extremadamente básica. Desearía poder jugar mejor la última línea, pero actualmente no tengo ideas. Llamada con
S(25)
.El programa solo realiza un BFS simple sin almacenamiento en caché, por lo que es muy lento. Aquí está
S(97)
, para algunos resultados de muestra:fuente
Dyalog APL, 49 caracteres / bytes *
Algoritmo descaradamente inspirado por la respuesta de @CChak .
Ejemplo:
Sin golf:
* Dyalog APL admite un conjunto de caracteres heredado que tiene los símbolos APL asignados a los valores superiores de 128 bytes. Por lo tanto, un programa APL que solo usa caracteres ASCII y símbolos APL puede considerarse bytes == caracteres.
fuente
Pitón, 183
No puedo garantizar que este se mantenga dentro del doble del programa óptimo para números pares, pero es eficiente. Para todas las entradas válidas
0 <= n < 65536
, es esencialmente instantáneo y genera un programa de como máximo 33 instrucciones. Para un tamaño de registro arbitrarion
(después de corregir esa constante), tomaríaO(n)
tiempo con, como máximo2n+1
instrucciones.Alguna lógica binaria
Cualquier número impar
n
se puede llegar en 31 pasos: hacery+=x
, conseguirx,y = 1,1
, y luego seguir doblandox
conx+=x
(por primera duplicación hacerlox+=y
, ya quex
es extraño para empezar).x
alcanzará cada potencia de 2 de esta manera (es solo un desplazamiento a la izquierda), por lo que puede configurar cualquier bit dey
1 agregando la potencia correspondiente de 2. Dado que estamos utilizando registros de 16 bits, y cada bit excepto para la primera toma una duplicación para alcanzar y unay+=x
para establecer, obtenemos un máximo de 31 operaciones.Cualquier número par
n
es solo una potencia de 2, llámeloa
, multiplicado por un número impar, llámelom
; es decirn = 2^a * m
, o equivalentementen = m << a
. Use el proceso anterior para obtenerm
, luego reiniciex
desplazándolo hacia la izquierda hasta que sea 0. Haga unx+=y
ajustex = m
y luego continúe duplicandox
, la primera vez usandox+=y
y luego usandox+=x
.Sea lo que
a
sea, se necesitan16-a
turnosx
para obtenery=m
y una
turno adicional para restablecerx=0
. Otrosa
cambios dex
ocurrirán despuésx=m
. Entonces16+a
se usa un total de turnos. Hay hasta16-a
bits que deben configurarse para obtenerm
, y cada uno de ellos tomará unoy+=x
. Finalmente, necesitamos un paso adicionalx=0
para establecerlo en mx+=y
,. Por lo tanto, se necesitan como máximo 33 pasos para obtener cualquier número par.Puede, por supuesto, generalizar esto a cualquier tamaño de registro, en cuyo caso siempre toma como máximo
2n-1
y2n+1
opta porn
enteros pares e impares , respectivamente.Óptima
Este algoritmo produce un programa que es casi óptimo (es decir, dentro de
2n+2
sin
es el número mínimo de pasos) para números impares. Para un número impar dadon
, si elm
bit th es el primer 1, entonces cualquier programa toma al menosm
pasos para llegar ax=n
oy=n
, ya que la operación que aumenta los valores de los registros más rápido esx+=x
oy+=y
(es decir, duplicaciones) y se necesitanm
duplicaciones para llegar a elm
th bit de 1. Dado que este algoritmo toma la mayoría de los2m
pasos (a lo sumo dos por duplicación, uno para el turno y unoy+=x
), cualquier número impar se representa casi de manera óptima.Los números pares no son tan buenos, ya que siempre usa 16 operaciones para restablecer
x
antes que nada, y 8, por ejemplo, se puede alcanzar en 5 pasos.Curiosamente, el algoritmo anterior nunca usa
y+=y
en absoluto, ya quey
que siempre se mantiene extraño. En ese caso, puede encontrar el programa más corto para el conjunto restringido de solo 3 operaciones.Pruebas
Escribí una prueba simple para verificar que mi solución realmente produce resultados correctos, y nunca supera los 33 pasos, para todas las entradas válidas (
0 <= n < 65536
).Además, intenté hacer un análisis empírico para comparar la salida de mi solución con las salidas óptimas; sin embargo, resulta que la búsqueda de amplitud es demasiado ineficiente para obtener la longitud mínima de salida para cada entrada válida
n
. Por ejemplo, el uso de BFS para buscar la salidan = 65535
no termina en un período de tiempo razonable. Sin embargo, me he idobfs()
y estoy abierto a sugerencias.Sin embargo, probé mi propia solución contra la de @ CChak (implementada en Python aquí como
U
). Esperaba que al mío le iría peor, ya que es drásticamente ineficiente para números pares más pequeños, pero promediado en todo el rango de dos maneras, la mina produjo una producción de longitud en promedio de 10.8% a 12.3% más corta. Pensé que tal vez esto se debía a una mejor eficiencia de mi propia solución en números impares, así queV
usa el mío en números impares y @ CChak en números pares, peroV
está en el medio (aproximadamente 10% más corto queU
, 3% más largo queS
).fuente
x,y='xy'
era posible hasta ahora. Desafortunadamente, no puedo pensar en una forma de reescribir de manerac*b+e*2
concisa con el%
formato.S(2)
la salida es realmente larga?S(2)
siendo el más corto con 19). No llevo la cuenta dex
yy
de manera explícita, por lo que a pesar de quex
llega a los 2 después del segundo paso, no obstante continúa para restablecerx
a 0. Siento como si tiene que haber una mejor solución, pero hasta el momento no puedo pensar uno.