O teorema dos quatro quadrados de Lagrange nos diz que qualquer número natural pode ser representado como a soma de quatro números quadrados. Sua tarefa é escrever um programa que faça isso.
Entrada: um número natural (abaixo de 1 bilhão)
Saída: quatro números cujos quadrados somam esse número (a ordem não importa)
Nota: Você não precisa fazer uma pesquisa de força bruta! Detalhes aqui e aqui . Se houver uma função que trivialize esse problema (determinarei), isso não será permitido. Funções primárias automatizadas e raiz quadrada são permitidas. Se houver mais de uma representação, qualquer uma está correta. Se você optar por fazer força bruta, ela deverá ser executada dentro de um prazo razoável (3 minutos)
entrada de amostra
123456789
saída de amostra (qualquer uma é boa)
10601 3328 2 0
10601 3328 2
Respostas:
CJam, 50 bytes
Minha terceira (e final, prometo) resposta. Essa abordagem baseia-se fortemente na resposta do primo .
Experimente on-line no intérprete CJam .
Uso
fundo
Depois de ver o algoritmo atualizado do primo, tive que ver como a implementação do CJam seria pontuada:
Apenas 58 bytes! Esse algoritmo é executado em tempo quase constante e não exibe muita variação para diferentes valores de
N
. Vamos mudar isso ...Em vez de começar
floor(sqrt(N))
e diminuir, podemos começar em1
e incrementar. Isso economiza 4 bytes.Em vez de expressar
N
como4**a * b
, podemos expressá-lo comop**(2a) * b
- ondep
é o menor fator primordial deN
- para economizar mais 1 byte.A modificação anterior nos permite mudar ligeiramente a implementação (sem tocar o próprio algoritmo): Em vez de dividir
N
porp**(2a)
e multiplicar a solução porp**a
, podemos restringir directamente as possíveis soluções para os múltiplos dep**a
. Isso economiza mais 2 bytes.Não restringir o primeiro número inteiro a múltiplos de
p**a
salva um byte adicional.Algoritmo final
Encontre
a
eb
tal queN = p**(2a) * b
, ondeb
não é um múltiplo dep**2
ep
seja o menor fator primo deN
.Set
j = p**a
.Set
k = floor(sqrt(N - j**2) / A) * A
.Set
l = floor(sqrt(N - j**2 - k**2) / A) * A
.Set
m = floor(sqrt(N - j**2 - k**2 - l**2) / A) * A
.Se
N - j**2 - k**2 - l**2 - m**2 > 0
, definaj = j + 1
e volte para a etapa 3.Isso pode ser implementado da seguinte maneira:
Benchmarks
Executei todas as 5 versões em todos os números inteiros positivos até 999.999.999 no meu Intel Core i7-3770, medi o tempo de execução e contei as iterações necessárias para encontrar uma solução.
A tabela a seguir mostra o número médio de iterações e o tempo de execução para um único número inteiro:
Com apenas 4 iterações e 6,6 microssegundos por número inteiro, o algoritmo do primo é incrivelmente rápido.
Começando em
floor(sqrt(N))
faz mais sentido, pois isso nos deixa com valores menores para a soma dos três quadrados restantes. Como esperado, a partir de 1 é muito mais lento.Este é um exemplo clássico de uma boa ideia mal implementada. Para realmente reduzir o tamanho do código, contamos com
mF
o fator de número inteiroN
. Embora a versão 3 exija menos iterações que a versão 2, é muito mais lenta na prática.Embora o algoritmo não mude, a versão 4 é muito mais lenta. Isso ocorre porque ele executa uma divisão de ponto flutuante adicional e uma multiplicação de números inteiros em cada iteração.
Para a entrada
N = p**(2a) ** b
, o algoritmo 5 exigirá(k - 1) * p**a + 1
iterações, ondek
é o número de iterações 4 que o algoritmo requer. Sek = 1
oua = 0
, isso não faz diferença.No entanto, qualquer entrada do formulário
4**a * (4**c * (8 * d + 7) + 1)
pode ter um desempenho muito ruim. Para o valor inicialj = p**a
,N - 4**a = 4**(a + c) * (8 * d + 7)
, por isso não pode ser expresso como uma soma de três quadrados. Assim,k > 1
e pelo menosp**a
iterações são necessárias.Felizmente, o algoritmo original do primo é incrivelmente rápido e
N < 1,000,000,000
. O pior caso que pude encontrar à mão é o265,289,728 = 4**10 * (4**1 * (7 * 8 + 7) + 1)
que requer 6.145 iterações. O tempo de execução é inferior a 300 ms na minha máquina. Em média, esta versão é 13,5 vezes mais lenta que a implementação do algoritmo do primo.fonte
N
como4**a * b
, podemos expressá-lo comop**(2a) * b
". Isso é realmente uma melhoria . Eu gostaria de ter incluído isso, mas foi muito mais longo (o ideal é encontrar o maior fator quadrado perfeito). "Iniciar com 1 e incrementar salva 4 bytes." Isto é definitivamente mais lento. O tempo de execução para qualquer intervalo é de 4-5 vezes maior. "Todos os números inteiros positivos até 999.999.999 levaram 24,67 horas, fornecendo um tempo médio de execução de 0,0888 milissegundos por número inteiro". Perl só levou 2,5 horas para triturar toda a gama, ea tradução Python é 10x mais rápido;)p**a
é uma melhoria, mas é pequena. A divisão pelo maior fator quadrado perfeito faz uma grande diferença ao iniciar a partir de 1; ainda é uma melhoria ao iniciar a parte inteira da raiz quadrada. Implementá-lo custaria apenas mais dois bytes. O tempo de execução abismal parece ser devido às minhas melhorias, não ao CJam. Vou executar novamente os testes para todos os algoritmos (incluindo o que você propôs), contando as iterações em vez de medir o tempo da parede. Vamos ver quanto tempo que leva ...1\
troque-o por 1 (acumulador),mF
empurre sua fatoração e{~2/#*}/
eleva todos os fatores primos ao seu expoente dividido por dois, depois o multiplique pelo acumulador. Para a implementação direta do seu algoritmo, isso adiciona apenas 2 bytes. A pequena diferença é principalmente devido à maneira estranha eu tive que encontrar o expoente de 4, desde CJam não (parecem) ter um enquanto laço ...FRACTRAN:
15698 fraçõesComo esse é um problema clássico da teoria dos números, que melhor maneira de resolver isso do que usar números!
Toma na entrada o formato 2 n × 193 e produz 3 a × 5 b × 7 c × 11 d . Pode ser executado em 3 minutos, se você tem um realmente bom intérprete. Talvez.
Sugestão
O código é equivalente ao seguinte pseudo-Python:
fonte
Mathematica
61 6651Três métodos são mostrados. Somente a primeira abordagem atende ao requisito de tempo.
1-FindInstance (51 caracteres)
Isso retorna uma única solução da equação.
Exemplos e horários
2-IntegerPartitions
Isso funciona também, mas é muito lento para atender aos requisitos de velocidade.
Range[0, Floor@Sqrt@n]^2
é o conjunto de todos os quadrados menores que a raiz quadrada den
(o maior quadrado possível na partição).{4}
requer que as partições inteirasn
consistam em 4 elementos do conjunto de quadrados mencionado acima.1
, dentro da funçãoIntegerPartitions
retorna a primeira solução.[[1]]
remove os aparelhos externos; a solução foi retornada como um conjunto de um elemento.3-PowerRepresentations
PowerRepresentations retorna todas as soluções para o problema dos 4 quadrados. Também pode resolver somas de outros poderes.
PowersRepresentations retorna, em menos de 5 segundos, as 181 maneiras de expressar 123456789 como a soma de 4 quadrados:
No entanto, é muito lento para outras somas.
fonte
IntegerPartitions
. Como você pode ver pelos tempos, a velocidade varia muito, dependendo de o primeiro (maior) número estar próximo da raiz quadrada den
. Obrigado por capturar a violação de especificação na versão anterior.f[805306368]
? Sem dividir por potências de 4 primeiro, minha solução leva 0,05 s para 999999999; Eu abortada a referência para 805306368 após 5 minutos ...f[805306368]
retorna{16384, 16384, 16384}
após 21 minutos. Eu usei {3} no lugar de {4}. A tentativa de resolvê-lo com uma soma de quatro quadrados diferentes de zero não teve êxito após várias horas de execução.IntegerPartitions[n,4,Range[Floor@Sqrt@n]^2
deve funcionar. No entanto, acho que você não deve usar o método 1 para sua pontuação, pois ele não cumpre o prazo especificado na pergunta.Perl -
116 bytes87 bytes (veja a atualização abaixo)Contando o shebang como um byte, novas linhas foram adicionadas à sanidade horizontal.
Algo como uma combinação de envio de código mais rápido para código-golfe .
A complexidade média (pior?) Do caso parece ser
O (log n)O (n 0,07 ) . Nada que encontrei é mais lento que 0,001s e verifiquei todo o intervalo de 900000000 a 999999999 . Se você encontrar algo que demore significativamente mais do que isso, ~ 0,1s ou mais, entre em contato.Uso da amostra
Os dois últimos parecem ser os piores cenários para outros envios. Nos dois casos, a solução mostrada é literalmente a primeira coisa verificada. Pois
123456789
é o segundo.Se você deseja testar um intervalo de valores, pode usar o seguinte script:
Melhor quando canalizado para um arquivo. O intervalo
1..1000000
leva cerca de 14s no meu computador (71000 valores por segundo) e o intervalo999000000..1000000000
leva cerca de 20s (50000 valores por segundo), consistente com a complexidade média de O (log n) .Atualizar
Edit : Acontece que este algoritmo é muito semelhante ao que tem sido usado por calculadoras mentais há pelo menos um século .
Desde a publicação original, verifiquei todos os valores no intervalo de 1..1000000000 . O comportamento do "pior caso" foi exibido pelo valor 699731569 , que testou um total geral de 190 combinações antes de chegar a uma solução. Se você considera 190 uma pequena constante - e eu certamente considero - o pior comportamento possível no intervalo necessário pode ser considerado O (1) . Ou seja, tão rápido quanto procurar a solução em uma mesa gigante e, em média, possivelmente mais rápido.
Outra coisa, porém. Após 190 iterações, qualquer coisa maior que 144400 nem chegou além da primeira passagem. A lógica do percurso pela primeira vez é inútil - nem sequer é usada. O código acima pode ser bastante reduzido:
Que realiza apenas a primeira passagem da pesquisa. Precisamos confirmar que não há valores abaixo de 144400 que precisem da segunda passagem, no entanto:
Resumindo, para o intervalo de 1 a 1000000000 , existe uma solução de tempo quase constante e você está olhando para ela.
Atualização atualizada
@Dennis e eu fizemos várias melhorias neste algoritmo. Você pode acompanhar o progresso nos comentários abaixo e a discussão subsequente, se isso lhe interessar. O número médio de iterações para o intervalo necessário caiu de pouco mais de 4 para 1,229 , e o tempo necessário para testar todos os valores para 1..1000000000 foi aprimorado de 18m 54s para 2m 41s. O pior caso anteriormente exigia 190 iterações; o pior caso agora, 854382778 , precisa apenas de 21 .
O código final do Python é o seguinte:
Isso usa duas tabelas de correção pré-calculadas, uma com 10kb de tamanho e a outra com 253kb. O código acima inclui as funções de gerador para essas tabelas, embora provavelmente devam ser calculadas em tempo de compilação.
Uma versão com tabelas de correção de tamanho mais modesto pode ser encontrada aqui: http://codepad.org/1ebJC2OV Esta versão requer uma média de 1.620 iterações por termo, com o pior caso de 38 , e todo o intervalo é executado em cerca de 3m 21s. Um pouco de tempo é compensado, usando bit
and
a bit para correção b , em vez de módulo.Melhorias
Valores pares têm mais probabilidade de produzir uma solução do que valores ímpares.
O artigo de cálculo mental, vinculado anteriormente, observa que se, após remover todos os fatores de quatro, o valor a ser decomposto for par, esse valor poderá ser dividido por dois e a solução reconstruída:
Embora isso possa fazer sentido para o cálculo mental (valores menores tendem a ser mais fáceis de calcular), não faz muito sentido algoritmicamente. Se você pegar 256 pares aleatórios de 4 e examinar a soma dos quadrados do módulo 8 , verá que os valores 1 , 3 , 5 e 7 são alcançados, em média, 32 vezes. No entanto, os valores 2 e 6 são atingidos 48 vezes. A multiplicação dos valores ímpares por 2 encontrará uma solução, em média, em 33% menos iterações. A reconstrução é a seguinte:
Cuidado deve ser tomado para que um e b têm a mesma paridade, bem como c e d , mas se uma solução foi encontrada em tudo, uma ordenação adequada é garantido que existe.
Caminhos impossíveis não precisam ser verificados.
Depois de selecionar o segundo valor, b , já pode ser impossível a existência de uma solução, dados os possíveis resíduos quadráticos para qualquer módulo. Em vez de verificar de qualquer maneira, ou passar para a próxima iteração, o valor de b pode ser 'corrigido', diminuindo-o pela menor quantidade possível de uma solução. As duas tabelas de correção armazenam esses valores, um para be o outro para c . Usar um módulo mais alto (mais precisamente, usar um módulo com relativamente menos resíduos quadráticos) resultará em uma melhoria melhor. O valor a não precisa de correção; modificando n para ser par, todos os valores dea são válidos.
fonte
Python 3 (177)
Depois de reduzirmos a entrada
N
para não ser divisível por 4, ela deve ser expressável como uma soma de quatro quadrados, onde um deles é o maior valor possívela=int(N**0.5)
ou um menor que isso, deixando apenas um pequeno restante para a soma dos outros três quadrados para cuidar. Isso reduz muito o espaço de pesquisa.Aqui está uma prova mais tarde, esse código sempre encontra uma solução. Queremos encontrar um
a
para quen-a^2
seja a soma de três quadrados. No Teorema dos Três Quadrados de Legendre , um número é a soma de três quadrados, a menos que seja a forma4^j(8*k+7)
. Em particular, esses números são 0 ou 3 (módulo 4).Mostramos que não dois consecutivos
a
podem fazer com que a quantidade restanteN-a^2
tenha tal forma para os dois valores consecutivos. Podemos fazer isso simplesmente criando uma tabelaa
e oN
módulo 4, observando issoN%4!=0
porque extraímos todos os poderes de 4 deN
.Porque não há dois consecutivos
a
dar(N-a*a)%4 in [0,3]
, um deles é seguro para uso. Portanto, avidamente usamos o maior possíveln
comn^2<=N
, en-1
. Desde entãoN<(n+1)^2
, o restanteN-a^2
a ser representado como uma soma de três quadrados é no máximo(n+1)^2 -(n-1)^2
, o que é igual4*n
. Portanto, basta verificar apenas valores até2*sqrt(n)
, que é exatamente o intervaloR
.Pode-se otimizar ainda mais o tempo de execução, parando após uma única solução, computando em vez de repetir o último valor
d
e pesquisando apenas entre valoresb<=c<=d
. Mas, mesmo sem essas otimizações, a pior instância que encontrei concluída em 45 segundos na minha máquina.A cadeia de "para x em R" é lamentável. Provavelmente, pode ser reduzido pela substituição ou substituição de cadeias, iterando sobre um único índice que codifica (a, b, c, d). Importar ferramentas de controle acabou não valendo a pena.
Editar: Alterado
int(2*n**.5)+1
de2*int(n**.5)+2
para tornar o argumento mais limpo, com a mesma contagem de caracteres.fonte
5 => (2, 1, 0, 0)
5 => (2, 1, 0, 0)
uso o Ideone 3.2.3 ou o Idle 3.2.2. O que você ganha?5 => (2, 1, 0, 0)
. Você leu o comentário? (Agora temos 3 comentários em uma linha que tem que trecho de código que pode manter a raia indo.?)5 => (2, 1, 0, 0)
, significa2^2 + 1^2 + 0^2 + 0^2 = 5
. Então, sim, nós podemos.5 => (2, 1, 0, 0)
está correto. Os exemplos na pergunta consideram 0 ^ 2 = 0 como um número quadrado válido. Por isso, interpretei (como acho que xnor) que a British Color conseguiu outra coisa. A cor britânica, como você não respondeu novamente, podemos supor que você realmente recebe2,1,0,0
?CJam ,
91907471 bytesCompacto, mas mais lento que minha outra abordagem.
Experimente online! Cole o código , digite o número inteiro desejado em Entrada e clique em Executar .
fundo
Esta postagem começou como uma resposta de 99 bytes do GolfScript . Embora ainda houvesse espaço para melhorias, o GolfScript não possui a função sqrt integrada. Eu mantive a versão GolfScript até a revisão 5 , pois era muito semelhante à versão CJam.
No entanto, as otimizações desde a revisão 6 exigem operadores que não estão disponíveis no GolfScript. Portanto, em vez de postar explicações separadas para os dois idiomas, decidi abandonar a versão menos competitiva (e muito mais lenta).
O algoritmo implementado calcula os números por força bruta:
Para entrada
m
, encontreN
eW
assim por diantem = 4**W * N
.Set
i = 257**2 * floor(sqrt(N/4))
.Set
i = i + 1
.Encontre números inteiros
j, k, l
comoi = 257**2 * j + 257 * k + l
, ondek, l < 257
.Verifique se
d = N - j**2 - k**2 - l**2
é um quadrado perfeito.Caso contrário, volte ao passo 3.
Imprimir
2**W * j, 2**W * k, 2**W * l, 2**W * sqrt(m)
.Exemplos
Os horários correspondem a um Intel Core i7-4700MQ.
Como funciona
fonte
C, 228
Isso é baseado no algoritmo da página da Wikipedia, que é uma força bruta O (n).
fonte
GolfScript,
133130129 bytesRápido, mas demorado. A nova linha pode ser removida.
Experimente online. Observe que o intérprete on-line tem um limite de 5 segundos, portanto, pode não funcionar para todos os números.
fundo
O algoritmo tira proveito do teorema de três quadrados de Legendre , que afirma que todo número natural n que não é da forma
pode ser expresso como a soma de três quadrados.
O algoritmo faz o seguinte:
Expresse o número como
4**i * j
.Encontre o maior inteiro
k
tal quek**2 <= j
ej - k**2
satisfaz a hipótese do teorema de três-quadrado de Legendre.Set
i = 0
.Verifique se
j - k**2 - (i / 252)**2 - (i % 252)**2
é um quadrado perfeito.Caso contrário, aumente
i
e volte para a etapa 4.Exemplos
Os horários correspondem a um Intel Core i7-4700MQ.
Como funciona
fonte
j-k-(i/252)-(i%252)
. Pelos seus comentários (não consigo ler o código), parece que você está falando sérioj-k-(i/252)^2-(i%252)^2
. BTW, o equivalente aj-k-(i/r)^2-(i%r)^2
, onde r = sqrt (k) pode economizar alguns personagens (e parece funcionar sem problemas mesmo para k = 0 no meu programa C.)j-k^2-(i/252)^2-(i%252)^2
. Ainda estou esperando o OP esclarecer se 0 é uma entrada válida ou não. Seu programa fornece1414 -nan 6 4.000000
informações0
.0/
=> falha! : P Fiz a sua rev 1 no meu laptop (i7-4700MQ, 8 GiB RAM). Em média, o tempo de execução é de 18,5 segundos.Rev 1: C, 190
Isso tem ainda mais memória do que a rev 0. O mesmo princípio: construa uma tabela com um valor positivo para todas as somas possíveis de 2 quadrados (e zero para os números que não são somas de dois quadrados), depois procure-a.
Nesta revisão, use uma matriz de em
short
vez dechar
para armazenar os hits, para que eu possa armazenar a raiz de um dos quadrados da tabela em vez de apenas uma bandeira. Isso simplifica a funçãop
(para decodificar a soma de 2 quadrados) consideravelmente, pois não há necessidade de um loop.O Windows tem um limite de 2 GB em matrizes. Eu posso contornar o
short s[15<<26]
que é uma matriz de 1006632960 elementos, o suficiente para cumprir as especificações. Infelizmente, o tamanho total do tempo de execução do programa ainda é superior a 2 GB e (apesar de ajustar as configurações do SO), não fui capaz de executar esse tamanho (embora seja teoricamente possível). O melhor que posso fazer éshort s[14<<26]
(939524096 elementos.)m*m
Deve ser estritamente menor que isso (30651 ^ 2 = 939483801.) No entanto, o programa funciona perfeitamente e deve funcionar em qualquer sistema operacional que não possua essa restrição.Código ungolfed
Rev 0 C, 219
Este é um animal com fome de memória. É necessário um array de 1 GB, calcula todas as somas possíveis de 2 quadrados e armazena um sinalizador para cada um no array. Em seguida, para a entrada do usuário z, ele procura na matriz duas somas de 2 quadrados ae za.
a função
p
então reconsitutes os quadrados originais que foram usadas para fazer as somas de 2 quadradosa
ez-a
e imprime-los, o primeiro de cada par como um número inteiro, o segundo como um duplo (se ele tem de ser todos os inteiros são necessários mais de dois caracteres,t
>m=t
.)O programa leva alguns minutos para criar a tabela de somas de quadrados (acho que isso se deve a problemas de gerenciamento de memória, vejo a alocação de memória subindo lentamente, em vez de saltar como seria de esperar.) No entanto, uma vez feito isso, produz respostas muito rapidamente (se vários números devem ser calculados, o programa a partir de então
scanf
pode ser colocado em um loop.código não destruído
Saída de exemplo
O primeiro é por pergunta. A segunda foi escolhida como difícil de pesquisar. Nesse caso, o programa deve procurar até 8192 ^ 2 + 8192 ^ 2 = 134217728, mas leva apenas alguns segundos depois que a tabela é criada.
fonte
#include <stdio.h>
(para scanf / printf) ou#include <math.h>
(para sqrt). vincula as bibliotecas necessárias automaticamente. Eu tenho que agradecer ao Dennis por isso (ele me disse sobre esta questão codegolf.stackexchange.com/a/26330/15599 ) A melhor dica de golfe que já tive.include
. Para compilação no Linux, você precisa da bandeira-lm
stdio
e várias outras bibliotecas, mas nemmath
mesmo com oinclude
? Pelo que entendi se você colocar o sinalizador do compilador, você não precisa doinclude
mesmo? Bem, está funcionando para mim, então não estou reclamando, obrigado novamente pela dica. BTW Espero postar uma resposta completamente diferente, aproveitando o teorema de Legendre (mas ele ainda usará umsqrt
.) #-lm
afeta o vinculador, não o compilador.gcc
opta por não exigir os protótipos para funções que "conhece", portanto, trabalha com ou sem as inclusões. No entanto, os arquivos de cabeçalho fornecem apenas protótipos de função, não as próprias funções. No Linux (mas não no Windows, aparentemente), a biblioteca matemática libm não faz parte das bibliotecas padrão; portanto, você precisa instruirld
para vincular a ela.Mathematica, 138 caracteresPortanto, verifica-se que isso produz resultados negativos e imaginários para determinadas entradas, conforme apontado por edc65 (por exemplo, 805306368), portanto, essa não é uma solução válida. Vou deixar por enquanto, e talvez, se realmente odeio meu tempo, voltarei e tentarei consertar.
Ou não qualificado:
Não olhei muito para os algoritmos, mas espero que seja a mesma ideia. Eu apenas vim com a solução óbvia e a aprimorei até que funcionasse. Eu testei para todos os números entre 1 e 1 bilhão e ... funciona. O teste leva apenas cerca de 100 segundos na minha máquina.
O bom disso é que, como b, c e d são definidos com atribuições atrasadas
:=
, eles não precisam ser redefinidos quando a é decrementado. Isso salvou algumas linhas extras que eu tinha antes. Eu poderia jogar mais e aninhar as partes redundantes, mas aqui está o primeiro rascunho.Ah, e você o executa como
S@123456789
e pode testá-lo com{S@#, Total[(S@#)^2]} & @ 123456789
ou# == Total[(S@#)^2]&[123456789]
. O teste exaustivo éEu usei uma declaração Print [] antes, mas isso diminuiu bastante a velocidade, mesmo que nunca seja chamada. Vai saber.
fonte
n - a^2 - b^2 - c^2
como variável e verificar sed^2
é igual a isso.a * 4^(2^k)
dek>=2
, tendo extraído todas as potências de 4, de modo quea
não seja um múltiplo de 4 (mas poderia ser par). Além disso, cada uma
possui 3 mod 4 ou o dobro desse número. O menor deles é 192.Haskell 123 + 3 = 126
Força bruta simples sobre quadrados pré-calculados.
Ele precisa da
-O
opção de compilação (adicionei 3 caracteres para isso). Demora menos de 1 minuto para o pior caso 999950883.Testado apenas no GHC.
fonte
C: 198 caracteresProvavelmente, posso apertar para pouco mais de 100 caracteres. O que eu mais gosto nessa solução é a quantidade mínima de lixo, apenas um loop for simples, fazendo o que um loop for deve fazer (o que é muito louco).
E fortemente prettificado:
Edit: Não é rápido o suficiente para todas as entradas, mas voltarei com outra solução. Vou deixar essa bagunça da operação ternária ficar a partir de agora.
fonte
Rev B: C, 179
Obrigado a @Dennis pelas melhorias. O restante da resposta abaixo não é atualizado da rev. A.
Rev A: C, 195
Muito mais rápido que minha outra resposta e com muito menos memória!
Isso usa http://en.wikipedia.org/wiki/Legendre%27s_three-square_theorem . Qualquer número que não seja da seguinte forma pode ser expresso como a soma de 3 quadrados (eu chamo isso de forma proibida):
4^a*(8b+7), or equivalently 4^a*(8b-1)
Observe que todos os números quadrados ímpares são da forma
(8b+1)
e todos os números quadrados pares são superficialmente da forma4b
. No entanto, isso oculta o fato de que todos os números pares são da forma4^a*(odd square)==4^a*(8b+1)
. Como resultado, o2^x-(any square number < 2^(x-1))
ímparx
será sempre da forma proibida. Portanto, esses números e seus múltiplos são casos difíceis, e é por isso que muitos dos programas aqui dividem as potências de 4 como primeiro passo.Conforme declarado na resposta de @ xnor,
N-a*a
não pode ter a forma proibida por 2 valores consecutivos dea
. Abaixo, apresento uma forma simplificada de sua tabela. Além do fato de que após a divisão por 4N%4
não pode ser igual a 0, observe que existem apenas 2 valores possíveis para(a*a)%4
.Portanto, queremos evitar valores
(N-a*a)
que podem ser da forma proibida, ou seja, aqueles onde(N-a*a)%4
é 3 ou 0. Como pode ser visto, isso não pode ocorrer para o mesmoN
com ímpares e pares(a*a)
.Então, meu algoritmo funciona assim:
Eu particularmente gosto da maneira como passo o passo 3. Acrescento 3 a
N
, de modo que o decremento seja necessário se(3+N-a*a)%4 =
3 ou 2. (mas não 1 ou 0.) Divida isso por 2 e todo o trabalho pode ser feito com uma expressão bastante simples .Código ungolfed
Observe o
for
loop únicoq
e use divisão / módulo para derivar os valores deb
ec
para ele. Tentei usara
como divisor em vez de 256 para salvar bytes, mas às vezes o valor dea
não estava certo e o programa travou, possivelmente por tempo indeterminado. 256 foi o melhor compromisso que posso usar em>>8
vez da/256
divisão.Resultado
Uma peculiaridade interessante é que, se você digitar um número quadrado,
N-(a*a)
= 0. Mas o programa detecta isso0%4
= 0 e diminui para o próximo quadrado abaixo. Como resultado, as entradas de números quadrados são sempre decompostas em um grupo de quadrados menores, a menos que sejam da forma4^x
.fonte
m=1
antesmain
. 2. Executescanf
nafor
declaração. 3. Use emfloat
vez dedouble
. 4.n%4<1
é mais curto do que!(n%4)
. 5. Existe um espaço obsoleto na string de formato do printf.n-=a*a
não funciona, porquea
pode ser modificado posteriormente (fornece respostas erradas e depende de um pequeno número de casos, como 100 + 7 = 107.) Incluí todo o resto. Seria bom para algo diminuir,printf
mas acho que a única resposta é mudar o idioma. A chave para a velocidade é estabelecer um bom valora
rapidamente. Escrito em C e com um espaço de pesquisa inferior a 256 ^ 2, este é provavelmente o programa mais rápido aqui.printf
declaração parece difícil sem usar uma macro ou uma matriz, o que adicionaria massa em outro lugar. Mudar idiomas parece o caminho "fácil". Sua abordagem pesaria 82 bytes no CJam.JavaScript -
175 191 176173 caracteresForça bruta, mas rápida.
Edite rápido, mas não o suficiente para algumas entradas desagradáveis. Eu tive que adicionar uma primeira etapa de redução pela multiplicação de 4.
Edit 2 Livre-se da função, produza dentro do loop e force a saída da contição
Editar 3 0 não é uma entrada válida
Ungolfed:
Saída de exemplo
fonte