El teorema de cuatro cuadrados de Lagrange nos dice que cualquier número natural puede representarse como la suma de cuatro números cuadrados. Su tarea es escribir un programa que haga esto.
Entrada: un número natural (menos de mil millones)
Salida: cuatro números cuyos cuadrados suman ese número (el orden no importa)
Nota: ¡No tiene que hacer una búsqueda de fuerza bruta! Detalles aquí y aquí . Si hay una función que trivializa este problema (lo determinaré), no está permitido. Se permiten funciones primarias automatizadas y raíz cuadrada. Si hay más de una representación, cualquiera está bien. Si elige hacer fuerza bruta, debe ejecutarse dentro de un tiempo razonable (3 minutos)
entrada de muestra
123456789
salida de muestra (cualquiera está bien)
10601 3328 2 0
10601 3328 2
Respuestas:
CJam, 50 bytes
Mi tercera (y última, lo prometo) respuesta. Este enfoque se basa en gran medida en la respuesta de primo .
Pruébelo en línea en el intérprete de CJam .
Uso
Antecedentes
Después de ver algoritmo de Primo actualizado, que tenía que ver cómo tendría una puntuación de aplicación Cjam:
¡Solo 58 bytes! Este algoritmo se realiza en un tiempo casi constante y no presenta mucha variación para diferentes valores de
N
. Cambiemos eso ...En lugar de comenzar en
floor(sqrt(N))
y disminuir, podemos comenzar en1
e incrementar. Esto ahorra 4 bytes.En lugar de expresar
N
como4**a * b
, podemos expresarlo comop**(2a) * b
- dondep
es el factor primo más pequeño deN
- para guardar 1 byte más.La modificación anterior nos permite cambiar ligeramente la implementación (sin tocar el algoritmo mismo): en lugar de dividir
N
porp**(2a)
y multiplicar la solución porp**a
, podemos restringir directamente las posibles soluciones a múltiplos dep**a
. Esto ahorra 2 bytes más.Sin restringir el primer entero a múltiplos de
p**a
guarda un byte adicional.Algoritmo final
Encuentre
a
yb
tal queN = p**(2a) * b
, dondeb
no sea múltiplo dep**2
yp
sea el factor primo más pequeño deN
.Conjunto
j = p**a
.Conjunto
k = floor(sqrt(N - j**2) / A) * A
.Conjunto
l = floor(sqrt(N - j**2 - k**2) / A) * A
.Conjunto
m = floor(sqrt(N - j**2 - k**2 - l**2) / A) * A
.Si
N - j**2 - k**2 - l**2 - m**2 > 0
, configurarj = j + 1
y volver al paso 3.Esto se puede implementar de la siguiente manera:
Puntos de referencia
Ejecuté las 5 versiones en todos los enteros positivos hasta 999,999,999 en mi Intel Core i7-3770, medí el tiempo de ejecución y conté las iteraciones necesarias para encontrar una solución.
La siguiente tabla muestra el número promedio de iteraciones y el tiempo de ejecución para un solo entero:
Con solo 4 iteraciones y 6.6 microsegundos por entero, el algoritmo de primo es increíblemente rápido.
Comenzar en
floor(sqrt(N))
tiene más sentido, ya que esto nos deja con valores más pequeños para la suma de los tres cuadrados restantes. Como se esperaba, comenzar en 1 es mucho más lento.Este es un ejemplo clásico de una buena idea mal implementada. Para reducir realmente el tamaño del código, confiamos en
mF
que factoriza el número enteroN
. Aunque la versión 3 requiere menos iteraciones que la versión 2, es mucho más lenta en la práctica.Aunque el algoritmo no cambia, la versión 4 es mucho más lenta. Esto se debe a que realiza una división de coma flotante adicional y una multiplicación entera en cada iteración.
Para la entrada
N = p**(2a) ** b
, el algoritmo 5 requerirá(k - 1) * p**a + 1
iteraciones, dondek
es la cantidad de iteraciones que requiere el algoritmo 4. Sik = 1
oa = 0
, esto no hace ninguna diferencia.Sin embargo, cualquier entrada del formulario
4**a * (4**c * (8 * d + 7) + 1)
puede funcionar bastante mal. Para el valor de inicioj = p**a
,N - 4**a = 4**(a + c) * (8 * d + 7)
, por lo que no se puede expresar como una suma de tres cuadrados. Por lo tanto,k > 1
y al menosp**a
se requieren iteraciones.Afortunadamente, el algoritmo original de primo es increíblemente rápido y
N < 1,000,000,000
. El peor caso que pude encontrar a mano es265,289,728 = 4**10 * (4**1 * (7 * 8 + 7) + 1)
, que requiere 6,145 iteraciones. El tiempo de ejecución es inferior a 300 ms en mi máquina. En promedio, esta versión es 13.5 veces más lenta que la implementación del algoritmo de primo.fuente
N
como4**a * b
, podemos expresarlo comop**(2a) * b
". Esto es realmente una mejora . Me hubiera gustado incluir esto, pero fue mucho más largo (lo ideal es encontrar el factor cuadrado perfecto más grande). "Comenzar con 1 e incrementar ahorra 4 bytes". Esto definitivamente es más lento. El tiempo de ejecución para cualquier rango dado es de 4 a 5 veces más largo. "Todos los enteros positivos hasta 999,999,999 tomaron 24.67 horas, lo que da un tiempo de ejecución promedio de 0.0888 milisegundos por entero". Perl solo tardó 2.5 horas en procesar todo el rango, y la traducción de Python es 10 veces más rápida;)p**a
es una mejora, pero es pequeña. Dividir por el factor cuadrado perfecto más grande hace una gran diferencia al comenzar desde 1; sigue siendo una mejora al comenzar desde la parte entera de la raíz cuadrada. Implementarlo costaría solo dos bytes más. El tiempo de ejecución abismal parece deberse a mis mejoras, no a CJam. Volveré a ejecutar las pruebas para todos los algoritmos (incluido el que propuso), contando las iteraciones en lugar de medir el tiempo de la pared. Veamos cuánto tiempo lleva eso ...1\
intercambia con 1 (acumulador),mF
empuja su factorización y{~2/#*}/
eleva cada factor primo a su exponente dividido por dos, luego lo multiplica con el acumulador. Para la implementación directa de su algoritmo, eso solo agrega 2 bytes. La pequeña diferencia se debe principalmente a la forma incómoda que tenía que encontrar el exponente de 4, ya que no Cjam (parece que) tener un tiempo de bucle ...FRACTRAN:
15698 fraccionesComo este es un problema clásico de la teoría de números, ¡qué mejor manera de resolverlo que usar números!
Toma entrada de la forma 2 n × 193 y emite 3 a × 5 b × 7 c × 11 d . Podría correr en 3 minutos si tiene un intérprete realmente bueno. Tal vez.
Insinuación
El código es equivalente al siguiente pseudo-Python:
fuente
Mathematica
61 6651Se muestran tres métodos. Solo el primer enfoque cumple el requisito de tiempo.
1-FindInstance (51 caracteres)
Esto devuelve una única solución a la ecuación.
Ejemplos y horarios
Particiones de 2 enteros
Esto también funciona, pero es demasiado lento para cumplir con el requisito de velocidad.
Range[0, Floor@Sqrt@n]^2
es el conjunto de todos los cuadrados menores que la raíz cuadrada den
(el cuadrado más grande posible en la partición).{4}
requiere que las particiones enterasn
constan de 4 elementos del conjunto de cuadrados mencionado anteriormente.1
, dentro de la funciónIntegerPartitions
devuelve la primera solución.[[1]]
elimina los tirantes externos; La solución se devolvió como un conjunto de un elemento.Representaciones de 3 poderes
PowerRepresentations devuelve todas las soluciones al problema de los 4 cuadrados. También puede resolver sumas de otros poderes.
PowersRepresentations devuelve, en menos de 5 segundos, las 181 formas de expresar 123456789 como la suma de 4 cuadrados:
Sin embargo, es demasiado lento para otras sumas.
fuente
IntegerPartitions
. Como puede ver en los tiempos, la velocidad varía mucho dependiendo de si el primer número (el más grande) está cerca de la raíz cuadrada den
. Gracias por detectar la violación de especificaciones en la versión anterior.f[805306368]
? Sin dividir por potencias de 4 primero, mi solución toma 0.05 s para 999999999; He abortado el punto de referencia para 805306368 después de 5 minutos ...f[805306368]
regresa{16384, 16384, 16384}
después de 21 minutos. Usé {3} en lugar de {4}. El intento de resolverlo con una suma de 4 cuadrados distintos de cero no tuvo éxito después de varias horas de ejecución.IntegerPartitions[n,4,Range[Floor@Sqrt@n]^2
debería funcionar también. Sin embargo, no creo que deba usar el método 1 para su puntaje, ya que no cumple con el límite de tiempo especificado en la pregunta.Perl -
116 bytes87 bytes (ver actualización a continuación)Contando el shebang como un byte, se agregaron nuevas líneas para la cordura horizontal.
Algo de una combinación de código de golf más rápido de envío de código .
La complejidad del caso promedio (¿peor?) Parece ser
O (log n)O (n 0.07 ) . Nada de lo que he encontrado funciona más lento que 0.001s, y he verificado todo el rango de 900000000 a 999999999 . Si encuentra algo que lleva mucho más tiempo que eso, ~ 0.1s o más, hágamelo saber.Uso de muestra
Los dos últimos de estos parecen ser los escenarios del peor de los casos para otras presentaciones. En ambos casos, la solución que se muestra es, literalmente, lo primero que se verifica. por
123456789
, es el segundo.Si desea probar un rango de valores, puede usar el siguiente script:
Mejor cuando se canaliza a un archivo. El rango
1..1000000
toma alrededor de 14 segundos en mi computadora (71000 valores por segundo), y el rango999000000..1000000000
toma alrededor de 20 segundos (50000 valores por segundo), de acuerdo con la complejidad promedio de O (log n) .Actualizar
Editar : Resulta que este algoritmo es muy similar a uno que ha sido utilizado por calculadoras mentales durante al menos un siglo .
Desde la publicación original, he verificado todos los valores en el rango de 1..1000000000 . El comportamiento del "peor de los casos" fue exhibido por el valor 699731569 , que probó un total de 190 combinaciones antes de llegar a una solución. Si considera que 190 es una constante pequeña, y ciertamente lo hago, el peor de los casos en el rango requerido puede considerarse O (1) . Es decir, tan rápido como buscar la solución desde una mesa gigante, y en promedio, posiblemente más rápido.
Sin embargo, otra cosa. Después de 190 iteraciones, cualquier cosa mayor que 144400 ni siquiera ha superado el primer paso. La lógica del primer recorrido transversal no tiene valor, ni siquiera se usa. El código anterior se puede acortar bastante:
Que solo realiza el primer paso de la búsqueda. Sin embargo, debemos confirmar que no hay valores por debajo de 144400 que necesiten la segunda pasada:
En resumen, para el rango 1..1000000000 , existe una solución de tiempo casi constante, y la está viendo.
Actualización actualizada
@Dennis y yo hemos realizado varias mejoras en este algoritmo. Puede seguir el progreso en los comentarios a continuación y la discusión posterior, si eso le interesa. El número promedio de iteraciones para el rango requerido se ha reducido de poco más de 4 a 1.229 , y el tiempo necesario para probar todos los valores para 1..1000000000 se ha mejorado de 18m 54s, a 2m 41s. El peor de los casos requería anteriormente 190 iteraciones; El peor de los casos ahora, 854382778 , solo necesita 21 .
El código final de Python es el siguiente:
Utiliza dos tablas de corrección calculadas previamente, una de 10 kb de tamaño y la otra de 253 kb. El código anterior incluye las funciones generadoras para estas tablas, aunque probablemente deberían calcularse en tiempo de compilación.
Puede encontrar una versión con tablas de corrección de tamaño más modesto aquí: http://codepad.org/1ebJC2OV Esta versión requiere un promedio de 1.620 iteraciones por término, con un peor caso de 38 , y el rango completo se ejecuta en aproximadamente 3 m 21 s. Se compensa un poco de tiempo, utilizando bitwise
and
para la corrección b , en lugar del módulo.Mejoras
Los valores pares tienen más probabilidades de producir una solución que los valores impares.
El artículo de cálculo mental vinculado a notas anteriores señala que si, después de eliminar todos los factores de cuatro, el valor a descomponer es par, este valor se puede dividir por dos, y la solución reconstruida:
Aunque esto podría tener sentido para el cálculo mental (los valores más pequeños tienden a ser más fáciles de calcular), no tiene mucho sentido algorítmicamente. Si toma 256 tuplas aleatorias de 4 y examina la suma de los cuadrados del módulo 8 , encontrará que los valores 1 , 3 , 5 y 7 se alcanzan en promedio 32 veces. Sin embargo, los valores 2 y 6 se alcanzan cada uno 48 veces. Multiplicando valores impares por 2 encontrará una solución, en promedio, en 33% menos iteraciones. La reconstrucción es la siguiente:
El cuidado necesita ser tomado que una y B tienen la misma paridad, así como c y d , pero si se encontró una solución en absoluto, una ordenación adecuada está garantizado para existir.
No es necesario verificar las rutas imposibles.
Después de seleccionar el segundo valor, b , puede que ya sea imposible que exista una solución, dados los posibles residuos cuadráticos para cualquier módulo dado. En lugar de verificar de todos modos, o pasar a la siguiente iteración, el valor de b puede 'corregirse' disminuyéndolo en la cantidad más pequeña que pueda conducir a una solución. Las dos tablas de corrección almacenan estos valores, uno para b y el otro para c . Usar un módulo más alto (más exactamente, usar un módulo con relativamente menos residuos cuadráticos) dará como resultado una mejor mejora. El valor a no necesita ninguna corrección; modificando n para que sea par, todos los valores deuna son válidos.
fuente
Pitón 3 (177)
Después de reducir la entrada
N
para que no sea divisible por 4, debe ser expresable como una suma de cuatro cuadrados donde uno de ellos sea el valor más grande posiblea=int(N**0.5)
o uno menor que eso, dejando solo un pequeño resto para la suma de los otros tres cuadrados. para cuidar de. Esto reduce en gran medida el espacio de búsqueda.Aquí hay una prueba de que este código siempre encuentra una solución. Deseamos encontrar un valor
a
quen-a^2
sea la suma de tres cuadrados. Del teorema de tres cuadrados de Legendre , un número es la suma de tres cuadrados a menos que sea la forma4^j(8*k+7)
. En particular, tales números son 0 o 3 (módulo 4).Mostramos que no hay dos consecutivos
a
puedan hacer que la cantidad sobranteN-a^2
tenga esa forma para ambos valores consecutivos. Podemos hacerlo simplemente haciendo una tabla dea
yN
módulo 4, notando esoN%4!=0
porque hemos extraído todas las potencias de 4N
.Debido a que no hay dos consecutiva
a
dar(N-a*a)%4 in [0,3]
, uno de ellos es seguro de usar. Entonces, utilizamos con avidez la mayor cantidad posiblen
conn^2<=N
, yn-1
. ComoN<(n+1)^2
, el restoN-a^2
que se representará como una suma de tres cuadrados es como máximo(n+1)^2 -(n-1)^2
, lo que es igual4*n
. Por lo tanto, es suficiente verificar solo los valores hasta2*sqrt(n)
, que es exactamente el rangoR
.Uno podría optimizar aún más el tiempo de ejecución deteniéndose después de una única solución, calculando en lugar de iterar por el último valor
d
y buscando solo entre los valoresb<=c<=d
. Pero, incluso sin estas optimizaciones, la peor instancia que pude encontrar terminó en 45 segundos en mi máquina.La cadena de "para x en R" es lamentable. Probablemente se puede acortar mediante la sustitución o sustitución de cadenas iterando sobre un índice único que codifica (a, b, c, d). Importar itertools resultó que no valía la pena.
Editar: se cambió a
int(2*n**.5)+1
desde2*int(n**.5)+2
para hacer un argumento más limpio, el mismo carácter cuenta.fuente
5 => (2, 1, 0, 0)
5 => (2, 1, 0, 0)
ejecuto en Ideone 3.2.3 o en Idle 3.2.2. ¿Qué sacas?5 => (2, 1, 0, 0)
. ¿Incluso leíste el comentario? (Ahora tenemos 3 comentarios seguidos que tienen ese fragmento de código. ¿Podemos seguir con la racha?)5 => (2, 1, 0, 0)
, significa2^2 + 1^2 + 0^2 + 0^2 = 5
. Entonces sí podemos.5 => (2, 1, 0, 0)
es correcto. Los ejemplos en la pregunta consideran que 0 ^ 2 = 0 es un número cuadrado válido. Por lo tanto, interpreté (como creo que hizo xnor) que British Color obtuvo algo más. El color británico, como no ha respondido de nuevo, ¿podemos suponer que realmente lo consigue2,1,0,0
?CJam ,
91907471 bytesCompacto, pero más lento que mi otro enfoque.
Pruébalo en línea! Pegue el Código , escriba el número entero deseado en Entrada y haga clic en Ejecutar .
Antecedentes
Esta publicación comenzó como una respuesta de 99 bytes de GolfScript . Si bien todavía había margen de mejora, GolfScript carece de la función sqrt incorporada. Mantuve la versión de GolfScript hasta la revisión 5 , ya que era muy similar a la versión de CJam.
Sin embargo, las optimizaciones desde la revisión 6 requieren operadores que no están disponibles en GolfScript, por lo que en lugar de publicar explicaciones separadas para ambos idiomas, decidí abandonar la versión menos competitiva (y mucho más lenta).
El algoritmo implementado calcula los números por fuerza bruta:
Para entrada
m
, busqueN
yW
tal quem = 4**W * N
.Conjunto
i = 257**2 * floor(sqrt(N/4))
.Conjunto
i = i + 1
.Encuentra enteros
j, k, l
tales quei = 257**2 * j + 257 * k + l
, dondek, l < 257
.Comprueba si
d = N - j**2 - k**2 - l**2
es un cuadrado perfecto.Si no es así, y regrese al paso 3.
Imprimir
2**W * j, 2**W * k, 2**W * l, 2**W * sqrt(m)
.Ejemplos
Los tiempos corresponden a un Intel Core i7-4700MQ.
Cómo funciona
fuente
C, 228
Esto se basa en el algoritmo en la página de Wikipedia, que es una fuerza bruta O (n).
fuente
GolfScript,
133130129 bytesRápido, pero largo. La nueva línea se puede eliminar.
Pruébalo en línea.Tenga en cuenta que el intérprete en línea tiene un límite de tiempo de 5 segundos, por lo que podría no funcionar para todos los números.
Antecedentes
El algoritmo aprovecha el teorema de tres cuadrados de Legendre , que establece que cada número natural n que no tiene la forma
se puede expresar como la suma de tres cuadrados.
El algoritmo hace lo siguiente:
Exprese el número como
4**i * j
.Encontrar el mayor entero
k
tal quek**2 <= j
yj - k**2
satisface las hipótesis del Teorema de tres cuadrados de Legendre.Conjunto
i = 0
.Comprueba si
j - k**2 - (i / 252)**2 - (i % 252)**2
es un cuadrado perfecto.Si no es así, incremente
i
y regrese al paso 4.Ejemplos
Los tiempos corresponden a un Intel Core i7-4700MQ.
Cómo funciona
fuente
j-k-(i/252)-(i%252)
. De tus comentarios (no puedo leer el código), parece que te refieresj-k-(i/252)^2-(i%252)^2
. Por cierto, el equivalente dej-k-(i/r)^2-(i%r)^2
donde r = sqrt (k) puede guardar algunos caracteres (y parece funcionar sin problemas incluso para k = 0 en mi programa C).j-k^2-(i/252)^2-(i%252)^2
. Todavía estoy esperando que el OP aclare si 0 es una entrada válida o no. Su programa da1414 -nan 6 4.000000
para la entrada0
.0/
=> crash! : P He ejecutado su rev 1 en mi computadora portátil (i7-4700MQ, 8 GiB RAM). En promedio, el tiempo de ejecución es de 18.5 segundos.Rev 1: C, 190
Esto requiere aún más memoria que rev 0. El mismo principio: construir una tabla con un valor positivo para todas las sumas posibles de 2 cuadrados (y cero para aquellos números que no son sumas de dos cuadrados), luego búscalo.
En esta revisión, uso una matriz de en
short
lugar dechar
almacenar los golpes, para que pueda almacenar la raíz de uno de los cuadrados en la tabla en lugar de solo una bandera. Esto simplifica la funciónp
(para decodificar la suma de 2 cuadrados) considerablemente ya que no hay necesidad de un bucle.Windows tiene un límite de 2 GB en las matrices. Puedo sortear aquello con lo
short s[15<<26]
que hay una matriz de elementos 1006632960, suficiente para cumplir con la especificación. Por desgracia, el tamaño total de tiempo de ejecución del programa es de más de 2 GB y (a pesar de ajustar las configuraciones del sistema operativo) no he sido capaz de ejecutar más de este tamaño (aunque en teoría es posible.) Lo mejor que puedo hacer esshort s[14<<26]
(939524096 elementos.)m*m
Debe ser estrictamente menor que esto (30651 ^ 2 = 939483801.) Sin embargo, el programa se ejecuta perfectamente y debería funcionar en cualquier sistema operativo que no tenga esta restricción.Código sin golf
Rev 0 C, 219
Esta es una bestia hambrienta de memoria. Se necesita una matriz de 1 GB, calcula todas las sumas posibles de 2 cuadrados y almacena una bandera para cada una en la matriz. Luego, para la entrada de usuario z, busca en la matriz dos sumas de 2 cuadrados ay za.
la función
p
luego reconstituye los cuadrados originales que se usaron para hacer las sumas de 2 cuadradosa
y losz-a
imprime, el primero de cada par como un entero, el segundo como un doble (si tiene que ser todos los enteros, se necesitan dos caracteres más,t
>m=t
.)El programa tarda un par de minutos en construir la tabla de sumas de cuadrados (creo que esto se debe a problemas de administración de memoria, veo que la asignación de memoria aumenta lentamente en lugar de saltar como cabría esperar). Sin embargo, una vez hecho esto produce respuestas muy rápidamente (si se calculan varios números, el programa en
scanf
adelante se puede poner en un bucle.código sin golf
Salida de ejemplo
El primero es por la pregunta. El segundo fue elegido como uno difícil de buscar. En este caso, el programa tiene que buscar hasta 8192 ^ 2 + 8192 ^ 2 = 134217728, pero solo toma unos segundos una vez que se construye la tabla.
fuente
#include <stdio.h>
(para scanf / printf) o#include <math.h>
(para sqrt.) El compilador enlaza las bibliotecas necesarias automáticamente. Tengo que agradecer a Dennis por eso (me dijo en esta pregunta codegolf.stackexchange.com/a/26330/15599 ) El mejor consejo de golf que he tenido.include
. Para compilar en Linux, necesita la bandera-lm
stdio
y varias otras bibliotecas, pero nimath
siquiera con elinclude
? Por lo que entiendo que si pones el indicador del compilador, ¿no necesitas el deinclude
todos modos? Bueno, me está funcionando, así que no me estoy quejando, gracias de nuevo por el consejo. Por cierto, espero publicar una respuesta completamente diferente aprovechando el teorema de Legendre (pero aún usará asqrt
.)-lm
afecta al enlazador, no al compilador.gcc
opta por no requerir los prototipos para las funciones que "conoce", por lo que funciona con o sin las inclusiones. Sin embargo, los archivos de encabezado proporcionan solo prototipos de funciones, no las funciones mismas. En Linux (pero no en Windows, aparentemente), la biblioteca matemática libm no es parte de las bibliotecas estándar, por lo que debe instruirld
para vincularla.Mathematica, 138 caracteresResulta que esto produce resultados negativos e imaginarios para ciertas entradas como lo señala edc65 (por ejemplo, 805306368), por lo que esta no es una solución válida. Lo dejaré por ahora, y tal vez, si realmente odio mi tiempo, volveré e intentaré arreglarlo.
O sin desquitar:
No analicé demasiado los algoritmos, pero espero que esta sea la misma idea. Se me ocurrió la solución obvia y la ajusté hasta que funcionó. Lo probé para todos los números entre 1 y mil millones y ... funciona. La prueba solo toma alrededor de 100 segundos en mi máquina.
Lo bueno de esto es que, dado que b, cyd están definidos con asignaciones retrasadas
:=
, no es necesario redefinirlos cuando se disminuye a. Esto salvó algunas líneas adicionales que tenía antes. Podría jugar más golf y anidar las partes redundantes, pero aquí está el primer borrador.Ah, y lo ejecutas como
S@123456789
y puedes probarlo con{S@#, Total[(S@#)^2]} & @ 123456789
o# == Total[(S@#)^2]&[123456789]
. La prueba exhaustiva esUtilicé una declaración Print [] antes, pero eso la ralentizó mucho, aunque nunca se llama. Imagínate.
fuente
n - a^2 - b^2 - c^2
como una variable y verificar que sead^2
igual.a * 4^(2^k)
parak>=2
, después de haber extraído todas las potencias de 4 para quea
no sea un múltiplo de 4 (pero podría ser par). Además, cada unoa
es 3 mod 4, o el doble de ese número. El más pequeño es 192.Haskell 123 + 3 = 126
Fuerza bruta simple sobre cuadrados precalculados.
Necesita la
-O
opción de compilación (agregué 3 caracteres para esto). Se tarda menos de 1 minuto en el peor de los casos 999950883.Solo probado en GHC.
fuente
C: 198 caracteresProbablemente pueda reducirlo a poco más de 100 caracteres. Lo que me gusta de esta solución es la cantidad mínima de basura, solo un bucle for, haciendo lo que debe hacer un bucle for (que es una locura).
Y muy prettified:
Editar: no es lo suficientemente rápido para todas las entradas, pero volveré con otra solución. Dejaré que este lío de operaciones ternarias permanezca hasta ahora.
fuente
Rev B: C, 179
Gracias a @Dennis por las mejoras. El resto de la respuesta a continuación no se actualiza desde la rev. A.
Rev A: C, 195
¡Mucho más rápido que mi otra respuesta y con mucho menos memoria!
Esto utiliza http://en.wikipedia.org/wiki/Legendre%27s_three-square_theorem . Cualquier número que no sea de la siguiente forma puede expresarse como la suma de 3 cuadrados (a esto le llamo la forma prohibida):
4^a*(8b+7), or equivalently 4^a*(8b-1)
Tenga en cuenta que todos los números cuadrados impares son de la forma
(8b+1)
y todos los números cuadrados pares son superficialmente de la forma4b
. Sin embargo, esto oculta el hecho de que todos los números cuadrados pares son de la forma4^a*(odd square)==4^a*(8b+1)
. Como resultado2^x-(any square number < 2^(x-1))
para imparx
siempre será de la forma prohibida. Por lo tanto, estos números y sus múltiplos son casos difíciles, razón por la cual muchos de los programas aquí dividen las potencias de 4 como primer paso.Como se indica en la respuesta de @ xnor,
N-a*a
no puede tener la forma prohibida durante 2 valores consecutivos dea
. A continuación presento una forma simplificada de su tabla. Además del hecho de que después de la división por 4N%4
no puede ser igual a 0, tenga en cuenta que solo hay 2 valores posibles para(a*a)%4
.Por lo tanto, queremos evitar que los valores
(N-a*a)
puedan ser de la forma prohibida, es decir, aquellos en los que(N-a*a)%4
es 3 o 0. Como se puede ver, esto no puede sucederN
con los pares e impares(a*a)
.Entonces, mi algoritmo funciona así:
Particularmente me gusta la forma en que hago el paso 3. Agrego 3 a
N
, de modo que la disminución se requiere si(3+N-a*a)%4 =
3 o 2. (pero no 1 o 0.) Divida esto entre 2 y todo el trabajo se puede hacer con una expresión bastante simple .Código sin golf
Tenga en cuenta el
for
bucle únicoq
y el uso de la división / módulo para derivar los valores deb
yc
de él. Intenté usarloa
como un divisor en lugar de 256 para guardar bytes, pero a veces el valor dea
no era correcto y el programa se bloqueaba, posiblemente indefinidamente. 256 fue el mejor compromiso que puedo usar en>>8
lugar de/256
para la división.Salida
Una peculiaridad interesante es que si ingresa un número cuadrado,
N-(a*a)
= 0. Pero el programa detecta que0%4
= 0 y disminuye al siguiente cuadrado hacia abajo. Como resultado, las entradas de números cuadrados siempre se descomponen en un grupo de cuadrados más pequeños a menos que sean de la forma4^x
.fuente
m=1
antesmain
. 2. Ejecutarscanf
en lafor
declaración. 3. Use enfloat
lugar dedouble
. 4.n%4<1
es más corto que!(n%4)
. 5. Hay un espacio obsoleto en la cadena de formato de printf.n-=a*a
no funciona, porquea
puede modificarse después (da algunas respuestas incorrectas y se bloquea en un pequeño número de casos, como 100 + 7 = 107). Incluí todo el resto. Sería bueno acortar algo,printf
pero creo que la única respuesta es cambiar el idioma. La clave para acelerar es decidirse por un buen valora
rápidamente. Escrito en C y con un espacio de búsqueda de menos de 256 ^ 2, este es probablemente el programa más rápido aquí.printf
declaración parece difícil sin usar una macro o una matriz, lo que agregaría volumen en otros lugares. Cambiar los idiomas parece la forma "fácil". Su enfoque pesaría 82 bytes en CJam.JavaScript -
175 191 176173 caracteresFuerza bruta, pero rápida.
Edite rápido pero no lo suficiente para una entrada desagradable. Tuve que agregar un primer paso de reducción por multiplicaciones de 4.
Editar 2 Deshacerse de la función, salir dentro del bucle y luego forzar la contición de salida
Editar 3 0 no es una entrada válida
Sin golf:
Salida de ejemplo
fuente