Recientemente, en el recientemente lanzado Puzzling.SE , había un problema sobre los espías que arrojaban piedras a un río que en realidad era bastante desafiante:
Dos espías deben pasarse mutuamente dos números secretos (un número por espía), sin ser notados por sus enemigos. Han acordado un método para hacer esto usando solo 26 piedras indistinguibles de antemano.
Se encuentran en un río, donde hay un montón de 26 piedras. Comenzando con el primer espía, se turnan para arrojar un grupo de piedras al río: el primer espía arroja algunas piedras, luego la segunda, luego la primera otra vez ...
Cada espía debe lanzar al menos una piedra en su turno, hasta que todas las piedras se hayan ido.
Observan todos los lanzamientos y divergen cuando no hay más piedras. Guardan silencio todo el tiempo y no se intercambia información, excepto el número de piedras arrojadas en cada turno.
¿Cómo pueden intercambiar los números con éxito si los números pueden ser del 1 al M?
Su tarea es construir un par de programas spy1
y spy2
eso puede resolver este problema lo más alto posible M
.
Sus programas tomarán un número de cada uno 1
a su elección M
como entrada. Luego, spy1
generará un número que representa el número de piedras que arroja al río, que se ingresará a las spy2
cuales también generará un número para ingresar spy1
, y así sucesivamente hasta que los números generados se sumen 26
. Al final del lanzamiento, cada programa generará el número que cree que tenía el otro programa, que debe coincidir con el número que realmente se ingresó al otro programa.
Su programa debe funcionar para todos los posibles pares ordenados de números (i, j)
donde ambos i
y j
pueden variar de 1
a M
.
El programa que funcione para los más grandes M
será el ganador, con la primera respuesta que se publicará rompiendo un empate. Además, otorgaré una recompensa de reputación de +100 a la primera solución para la que se ha demostrado que funciona M >= 2286
, y +300 a la primera solución para la que se ha demostrado que funciona M >= 2535
.
Respuestas:
C #, M = 2535
Esto implementa * el sistema que describí matemáticamente en el hilo que provocó este concurso. Reclamo el bono de 300 repeticiones. El programa prueba automáticamente si lo ejecuta sin argumentos de línea de comandos o con
--test
un argumento de línea de comandos; para el espía 1, ejecuta con--spy1
, y para el espía 2 con--spy2
. En cada caso, toma el número que debo comunicar desde stdin, y luego realiza los lanzamientos a través de stdin y stdout.* En realidad, he encontrado una optimización que hace una gran diferencia (desde varios minutos para generar el árbol de decisión, hasta menos de un segundo); el árbol que genera es básicamente el mismo, pero todavía estoy trabajando en una prueba de eso. Si desea una implementación directa del sistema que describí en otra parte, consulte la revisión 2 , aunque es posible que desee realizar una copia de seguridad del registro adicional
Main
y de las mejores comunicaciones entre subprocesosTestSpyIO
.Si quieres un caso de prueba que completa en menos de un minuto, el cambio
N
a16
yM
a87
.Instrucciones para usuarios de Linux
Necesitará
mono-csc
compilar (en sistemas basados en Debian, está en elmono-devel
paquete) ymono
ejecutar (mono-runtime
paquete). Entonces los encantamientos sonetc.
fuente
yum install mono-core
(como root). 2.dmcs Puzzle625.cs
3.mono Puzzle625.exe --test
Programa de prueba de Python
Supongo que sería útil tener un programa de prueba que pueda verificar que su implementación esté funcionando. Ambos scripts a continuación funcionan con Python 2 o Python 3.
Programa de prueba (
tester.py
):Protocolo: se ejecutarán los dos programas espía especificados en la línea de comandos. Se espera que interactúen únicamente a través de stdin / stdout. Cada programa recibirá su número asignado como la primera línea de entrada. En cada turno, el espía 1 emite el número de piedras para lanzar, el espía 2 lee un número de stdin (que representa el lanzamiento del espía 1), y luego repiten (con las posiciones invertidas). Cuando cualquiera de los espías determina que se han arrojado 26 piedras, se detienen y emiten su conjetura para el número del otro espía.
Ejemplo de sesión con un spy1 compatible (
>
denota la entrada al espía)Si elige una muy grande M, y se tarda demasiado tiempo para correr, puede cambiar
test(
paratestrand(
en la última línea para ejecutar las pruebas al azar. En este último caso, deje el programa en funcionamiento durante al menos unos pocos miles de pruebas para generar confianza.Programa de ejemplo (
spy.py
), para M = 42:Ejemplo de uso:
fuente
Java, M = 2535
OK, aquí está mi implementación. En cada paso, un espía hace un movimiento. Cada posible movimiento representa un rango de códigos. El espía elige el movimiento que coincide con su código secreto. A medida que arrojan más piedras, el rango de códigos posibles se reduce hasta que, al final, para ambos espías, solo un código sigue siendo posible de acuerdo con los movimientos que hicieron.
Para recuperar los códigos secretos, puede reproducir todos los movimientos y calcular los rangos de códigos correspondientes. Al final, solo queda un código para cada espía, ese es el código secreto que quería transmitir.
Desafortunadamente, el algoritmo se basa en una gran tabla precalculada con cientos de miles de enteros. El método no podría aplicarse mentalmente con más de 8-10 piedras tal vez.
El primer archivo implementa el algoritmo de Spy. La parte estática
codeCount
calcula previamente una tabla que luego se usa para calcular cada movimiento. La segunda parte implementa 2 procedimientos, uno para seleccionar cuántas piedras lanzar, y el otro para reproducir movimientos para ayudar a reconstruir los códigos secretos.El segundo archivo prueba ampliamente la clase Spy. El método
simulate
simula el proceso. Utiliza la clase Spy para generar una secuencia de lanzamientos a partir de los códigos secretos y luego reconstruye los códigos a partir de la secuencia.Spy.java
ThrowingStones.java
Como referencia, la matriz codeCount precalculada contiene los siguientes valores:
Esto se relaciona directamente con los conjuntos de Tk de Peter Taylor. Tenemos:
fuente
range
campos. Pero estoy muy intrigado por su método de calcular la tabla. ¿Tienes una prueba de corrección? ¿Y está interesado en colaborar en un documento que discute el problema y calcula su solución?ksh / zsh, M = 126
En este sistema simple, cada espía arroja dígitos binarios al otro espía. En cada lanzamiento, la primera piedra se ignora, las siguientes piedras son cada bit 0, y la última piedra es el bit 1. Por ejemplo, para lanzar 20, un espía arrojaría 4 piedras (ignorar, 0, 2, agregar 4), luego tira 3 piedras (ignora, 8, suma 16), porque 4 + 16 = 20.
El conjunto de números no es contiguo. 0 a 126 están adentro, pero 127 está afuera. (Si ambos espías tienen 127, necesitan 28 piedras, pero tienen 26 piedras). Luego entran 128 a 158, 159 sale, 160 a 174 entran, 175 salen, 176 a 182 entran, 183 salen, 184 a 186 está adentro, 187 está afuera, y así sucesivamente.
Ejecute un intercambio automático con
ksh spy.sh 125 126
, o ejecute espías individuales conksh spy.sh spy1 125
yksh spy.sh spy2 126
. Aquí,ksh
puede ser ksh93, pdksh o zsh.EDITAR 14 de junio de 2014: Solucione un problema con algunos coprocesos en zsh. Estarían inactivos para siempre y no podrían salir, hasta que el usuario los matara.
fuente