Introducción
Supongamos que usted y su amigo están jugando un juego. Tu amigo piensa en una secuencia particular de n
bits, y tu tarea es deducir la secuencia haciéndoles preguntas. Sin embargo, el único tipo de pregunta que se le permite hacer es "¿Cuánto dura la subsecuencia común más larga de su secuencia y S
", dónde S
es cualquier secuencia de bits. Cuantas menos preguntas necesite, mejor.
La tarea
Su tarea es escribir un programa o función que tome como entrada un entero positivo n
y una secuencia binaria R
de longitud n
. La secuencia puede ser una matriz de enteros, una cadena o algún otro tipo razonable de su elección. Su programa generará la secuencia R
.
Su programa no puede acceder a la secuencia R
directamente. Lo único que se le permite hacer R
es darle como entrada a la función len_lcs
junto con otra secuencia binaria S
. La función len_lcs(R, S)
devuelve la longitud de la subsecuencia común más larga de R
y S
. Esto significa la secuencia más larga de bits que ocurre como una subsecuencia (no necesariamente contigua) en ambos R
y S
. Las entradas de las len_lcs
cuales pueden ser de diferentes longitudes. El programa debe invocar esta función R
y otras secuencias varias veces, y luego reconstruir la secuencia en R
función de esa información.
Ejemplo
Considere las entradas n = 4
y R = "1010"
. Primero, podríamos evaluar len_lcs(R, "110")
, lo que da 3
, ya que "110"
es la subsecuencia común más larga de "1010"
y "110"
. Entonces sabemos que R
se obtiene "110"
al insertar un bit en alguna posición. A continuación, podríamos intentar len_lcs(R, "0110")
, que regresa 3
ya que las subsecuencias comunes más largas son "110"
y "010"
, por "0110"
lo tanto, no es correcta. Luego intentamos len_lcs(R, "1010")
, que vuelve 4
. Ahora sabemos eso R == "1010"
, por lo que podemos devolver esa secuencia como la salida correcta. Esto requirió 3 llamadas a len_lcs
.
Reglas y puntaje
En este repositorio , encontrará un archivo llamado que subsequence_data.txt
contiene 100 secuencias binarias aleatorias de longitudes entre 75 y 124. Se generaron tomando tres flotadores aleatorios entre 0 y 1, tomando su promedio como a
, y luego volteando una a
moneda imparcial n
veces. Su puntaje es el número promedio de llamadas alen_lcs
estas secuencias, siendo menor el puntaje menor. Su envío debe registrar el número de llamadas. No hay límites de tiempo, excepto que debe ejecutar su programa en el archivo antes de enviarlo.
Su presentación será determinista. Los PRNG están permitidos, pero deben usar la fecha de hoy 200116
(o el equivalente más cercano) como semilla aleatoria. No está permitido optimizar su envío en relación con estos casos de prueba particulares. Si sospecho que esto está sucediendo, generaré un nuevo lote.
Este no es un código de golf, por lo que se recomienda escribir código legible. Rosetta Code tiene una página en la subsecuencia común más larga ; puede usar eso para implementar len_lcs
en su idioma de elección.
lcs
lugar de hacerlolen_lcs
.lcs(R, "01"*2*n)
regresaR
. ;) Pero eso podría funcionar si llamarlcs(R, S)
aumentaría el puntaje enlen(S)
lugar de 1, o algo así ...Respuestas:
Java,
99.0498.4697.66 llamadas lcs ()Cómo funciona
Exaple: Nuestra línea que se va a reconstruir es
00101
. Primero descubrimos cuántos ceros hay, comparando (aquí comparando = calculando lcs con la cadena original) por una cadena de solo ceros00000
. Luego pasamos por cada posición, volteamos0
a a1
y verificamos si ahora tenemos una subcadena común más larga. En caso afirmativo, acepte e ir a la siguiente posición, si no, voltee la corriente de1
nuevo a ay0
vaya a la siguiente posición:Optimizaciones
Esta es solo una implementación "ingenua", quizás sería posible encontrar un algoritmo más sofisticado que verifique varias posiciones a la vez. Pero no estoy seguro de si realmente hay uno mejor (por ejemplo, basado en el cálculo de bits de paridad similares al código de Hamming), ya que siempre puede evaluar la longitud de la subcadena común.
Para una línea de dígitos dada, este algoritmo necesita
#ofDigitsUntilTheLastOccurenceOf1 + 1
verificaciones exactas . (Reste uno si los últimos dígitos son an1
.)EDITAR: Una pequeña optimización: si solo verificamos el 2do último dígito y aún necesitamos insertar un
1
, sabemos con certeza que debe estar en la última posición, y podemos omitir la verificación correspondiente.EDIT2: Acabo de notar que puedes aplicar la idea anterior a las últimas
k
.Por supuesto, podría ser posible lograr un puntaje ligeramente más bajo con esta optimización, al reordenar todas las líneas primero, porque podría ser que obtenga más líneas con unas al final, pero eso obviamente sería una optimización para la actual. casos de prueba que ya no es gracioso.
Tiempo de ejecución
El límite superior es
O(#NumberOfBits)
.Código completo
Aquí el código completo:
fuente
1
, lo que equivale a que solo quedan ceros.