Quiero codificar de manera compacta enteros positivos x
en bits, de manera que permita la decodificación de nuevo en los enteros originales para un decodificador sin estado que conozca el valor máximo m
de cada uno x
; será posible decodificar de manera única la concatenación de codificaciones, como es el caso en la codificación Huffman.
[La introducción anterior motiva al resto, pero no es parte de la definición formal]
Notación: para cualquier número entero no negativo i
, n(i)
sea el número de bits necesarios para representar i
en binario; ese es el entero no negativo más pequeño k
tal quei>>k == 0
i : 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ..
n(i): 0 1 2 2 3 3 3 3 4 4 4 4 4 4 4 4 5 5 5 ..
Quiero una función F(x,m)
definida para 0<x
y x<=m
, con salida una cadena de ' 0
' o ' 1
', que tenga estas propiedades:
F(x,m)
tiene una longitud menor que2*n(x)
o2*n(m)-1
, la que sea menor.- Si
x<y
entonces:F(x,m)
no es más queF(y,m)
;F(x,m)
yF(y,m)
difieren en alguna posición sobre la longitud deF(x,m)
;- Hay una entrada
0
enF(x,m)
la primera posición.
- Cuando para ciertas
m
propiedades 1 y 2 no se definen de manera únicaF(x,m)
para todos los positivosx
como máximom
, rechazamos cualquier codificación que proporcione una codificación más largaF(x,m)
que alguna de otra manera aceptable, para la más pequeñax
para la que la longitud no coincide.
Nota: En lo anterior, de manera implícita, 0<x
, 0<y
, 0<m
, x<=m
, y y<=m
, por lo que F(x,m)
y F(y,m)
se definen.
Se solicita el programa más corto que, dado cualquiera x
y que m
cumpla con las restricciones anteriores y hasta 9 dígitos decimales, arroje un resultado F(x,m)
coherente con las reglas anteriores. El siguiente marco C (o su equivalente en otros lenguajes) no se cuenta:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define C(c) putchar((c)?'1':'0') // output '0' or '1'
#define S(s) fputs((s),stdout) // output a string
typedef unsigned long t; // at least 32 bits
void F(t x,t m); // prototype for F
int main(int argc,char *argv[]){
if(argc==3)F((t)atol(argv[1]),(t)atol(argv[2]));
return 0;}
void F(t x,t m) { // counting starts on next line
} // counting ends before this line
Comentario: la propiedad 1 limita agresivamente la longitud codificada; la propiedad 2 formaliza que es posible una decodificación inequívoca y canonicaliza la codificación; Afirmo (sin pruebas) que esto es suficiente para definir de forma exclusiva la salida de F
cuando m+1
es una potencia de dos, y que la propiedad 3 es suficiente para definir de manera única F
para otro m
.
Aquí hay una tabla parcial (hecha a mano; la primera versión publicada estaba plagada de errores, lo siento):
x : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
F(x,1) : empty
F(x,2) : 0 1
F(x,3) : 0 10 11
F(x,4) : 0 10 110 111
F(x,5) : 0 10 110 1110 1111
F(x,6) : 0 100 101 110 1110 1111
F(x,7) : 0 100 101 1100 1101 1110 1111
F(x,8) : 0 100 101 110 11100 11101 11110 11111
F(x,15) : 0 100 101 11000 11001 11010 11011 111000 111001 111010 111011 111100 111101 111110 111111
11111
, haciendo imposible la decodificación. Con la codificación propuesta, la concatenación de varias salidas se puede decodificar de forma exclusiva (incluso con elm
cambio dinámico máximo ). Traté de aclarar eso.Respuestas:
Python 3, 163 bytes
Ignora el
c=0
parámetro, eso es un truco de golf.Esto elige con avidez la representación más corta posible para cada número, sujeto a la condición de que los números restantes aún sean representables. Por lo tanto, por construcción, satisface exactamente las propiedades deseadas. Como resultado, en realidad no es tan difícil modificar este código para admitir un conjunto diferente de reglas de codificación.
Por ejemplo, aquí están las salidas hasta
m=15
:fuente
Python, 171
Tenga en cuenta que las líneas que parecen comenzar con 4 espacios en realidad comienzan con una pestaña.
Pruebas, con el script de prueba de bitpwner:
Explicación:
Todo esto se basa en la observación de que entre dos elementos consecutivos del código, F (x, m) y F (x + 1, m), siempre agregamos uno al número binario, luego lo multiplicamos por dos algunas veces. Si se siguen estos pasos, entonces es un código válido. El resto simplemente prueba para asegurarse de que sea lo suficientemente corto.
Golfs: 175 -> 171: cambiado 2 ** (2 * ... a 4 **
fuente
Python - 370
Crea un árbol huffman, lo equilibra para ajustarse a las reglas, luego hace un recorrido por el árbol para obtener los valores finales.
Para una solución más sucinta que se base en el patrón emergente, mire la respuesta de Isaac.
Es un buen ejemplo de cómo un enfoque completamente diferente puede resolver el problema.
Prueba:
Resultados:
fuente
F(7,8)
of111110
está mal, ya que tiene una longitud de 6, y "menor que2*n(x)
" implica menos de 6.