Le théorème des quatre carrés de Lagrange nous dit que tout nombre naturel peut être représenté comme la somme de quatre nombres carrés. Votre tâche consiste à écrire un programme qui fait cela.
Entrée: un nombre naturel (inférieur à 1 milliard)
Sortie: quatre nombres dont les carrés totalisent ce nombre (l'ordre n'a pas d'importance)
Remarque: vous n'avez pas à effectuer de recherche par force brute! Détails ici et ici . S'il existe une fonction qui banalise ce problème (je vais le déterminer), elle n'est pas autorisée. Les fonctions principales automatisées et la racine carrée sont autorisées. S'il y a plus d'une représentation, tout va bien. Si vous avez choisi de faire de la force brute, elle doit s'exécuter dans un délai raisonnable (3 minutes)
échantillon d'entrée
123456789
échantillon de sortie (soit est très bien)
10601 3328 2 0
10601 3328 2
Réponses:
CJam, 50 octets
Ma troisième (et dernière, je le promets) réponse. Cette approche est fortement basée sur la réponse de Primo .
Essayez-le en ligne dans l' interpréteur CJam .
Usage
Contexte
Après avoir vu l'algorithme mis à jour de primo, j'ai dû voir comment une implémentation CJam marquerait:
Seulement 58 octets! Cet algorithme fonctionne en temps presque constant et ne présente pas beaucoup de variation pour différentes valeurs de
N
. Changeons cela ...Au lieu de commencer à
floor(sqrt(N))
et décrémenter, nous pouvons commencer à1
et incrémenter. Cela économise 4 octets.Au lieu d'exprimer en
N
tant que4**a * b
, nous pouvons l'exprimer commep**(2a) * b
- oùp
est le plus petit facteur premier deN
- pour économiser 1 octet de plus.La modification précédente nous permet de modifier légèrement l'implémentation (sans toucher à l'algorithme lui-même): Au lieu de diviser
N
parp**(2a)
et de multiplier la solution parp**a
, nous pouvons directement restreindre les solutions possibles à des multiples dep**a
. Cela économise 2 octets supplémentaires.Ne pas restreindre le premier entier à des multiples de
p**a
sauvegarde un octet supplémentaire.Algorithme final
Trouvez
a
etb
tel queN = p**(2a) * b
, oùb
n'est pas un multiple dep**2
etp
est le plus petit facteur premier 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
.Si
N - j**2 - k**2 - l**2 - m**2 > 0
, réglezj = j + 1
et revenez à l'étape 3.Cela peut être implémenté comme suit:
Repères
J'ai exécuté les 5 versions sur tous les entiers positifs jusqu'à 999 999 999 sur mon Intel Core i7-3770, mesuré le temps d'exécution et compté les itérations nécessaires pour trouver une solution.
Le tableau suivant montre le nombre moyen d'itérations et le temps d'exécution pour un seul entier:
À seulement 4 itérations et 6,6 micro secondes par entier, l'algorithme de primo est incroyablement rapide.
Commencer par
floor(sqrt(N))
est plus logique, car cela nous laisse des valeurs plus petites pour la somme des trois carrés restants. Comme prévu, commencer à 1 est beaucoup plus lent.Ceci est un exemple classique d'une bonne idée mal mise en œuvre. Pour réellement réduire la taille du code, nous nous appuyons sur
mF
, qui factorise l'entierN
. Bien que la version 3 nécessite moins d'itérations que la version 2, elle est beaucoup plus lente en pratique.Bien que l'algorithme ne change pas, la version 4 est beaucoup plus lente. En effet, il effectue une division en virgule flottante supplémentaire et une multiplication entière à chaque itération.
Pour l'entrée
N = p**(2a) ** b
, l'algorithme 5 nécessitera des(k - 1) * p**a + 1
itérations, oùk
est le nombre d'itérations requis par l'algorithme 4. Sik = 1
oua = 0
, cela ne fait aucune différence.Cependant, toute entrée du formulaire
4**a * (4**c * (8 * d + 7) + 1)
peut fonctionner assez mal. Pour la valeur de départj = p**a
,N - 4**a = 4**(a + c) * (8 * d + 7)
elle ne peut donc pas être exprimée comme une somme de trois carrés. Ainsi,k > 1
et au moins desp**a
itérations sont nécessaires.Heureusement, l'algorithme original de primo est incroyablement rapide et
N < 1,000,000,000
. Le pire cas que j'ai pu trouver à la main est celui265,289,728 = 4**10 * (4**1 * (7 * 8 + 7) + 1)
qui nécessite 6 145 itérations. Le temps d'exécution est inférieur à 300 ms sur ma machine. En moyenne, cette version est 13,5 fois plus lente que l'implémentation de l'algorithme de primo.la source
N
comme4**a * b
, nous pouvons l'exprimer commep**(2a) * b
." Il s'agit en fait d'une amélioration . J'aurais aimé l'inclure, mais c'était beaucoup plus long (l'idéal est de trouver le plus grand facteur carré parfait). "Commencer par 1 et incrémenter économise 4 octets." C'est nettement plus lent. Le temps d'exécution pour une plage donnée est 4 à 5 fois plus long. "Tous les entiers positifs jusqu'à 999 999 999 ont pris 24,67 heures, ce qui donne un temps d'exécution moyen de 0,0888 milliseconde par entier." Perl n'a pris que 2,5 heures pour crunch toute la gamme, et la traduction Python est 10 fois plus rapide;)p**a
est une amélioration, mais elle est petite. La division par le plus grand facteur carré parfait fait une grande différence en partant de 1; c'est toujours une amélioration en partant de la partie entière de la racine carrée. Sa mise en œuvre ne coûterait que deux octets supplémentaires. Le temps d'exécution épouvantable semble être dû à mes améliorations, pas à CJam. Je vais relancer les tests pour tous les algorithmes (y compris celui que vous avez proposé), en comptant les itérations plutôt qu'en mesurant le temps de mur. Voyons voir combien de temps cela prend ...1\
échange avec 1 (accumulateur),mF
pousse sa factorisation et{~2/#*}/
élève chaque facteur premier à son exposant divisé par deux, puis multiplie-le avec l'accumulateur. Pour l'implémentation directe de votre algorithme, cela n'ajoute que 2 octets. La petite différence est principalement due à la façon maladroite je devais trouver l'exposant de 4, puisque CJAM ne (semblent) avoir en boucle ...FRACTRAN:
15698 fractionsPuisqu'il s'agit d'un problème classique de théorie des nombres, quelle meilleure façon de résoudre ce problème que d'utiliser des nombres!
Prend en entrée la forme 2 n × 193 et sort 3 a × 5 b × 7 c × 11 d . Peut fonctionner en 3 minutes si vous avez un très bon interprète. Peut être.
Allusion
Le code est équivalent au pseudo-Python suivant:
la source
Mathematica
61 6651Trois méthodes sont présentées. Seule la première approche répond aux exigences de temps.
1-FindInstance (51 caractères)
Cela renvoie une seule solution l'équation.
Exemples et délais
2-EntierPartitions
Cela fonctionne également, mais est trop lent pour répondre aux exigences de vitesse.
Range[0, Floor@Sqrt@n]^2
est l'ensemble de tous les carrés inférieur à la racine carrée den
(le plus grand carré possible dans la partition).{4}
nécessite que les partitions entières sen
composent de 4 éléments de l'ensemble de carrés susmentionné.1
, dans la fonctionIntegerPartitions
renvoie la première solution.[[1]]
supprime les accolades extérieures; la solution a été renvoyée sous la forme d'un ensemble d'un élément.3-PowerReprésentations
PowerRepresentations renvoie toutes les solutions au problème des 4 carrés. Il peut également résoudre des sommes d'autres pouvoirs.
PowersRepresentations renvoie, en moins de 5 secondes, les 181 façons d'exprimer 123456789 comme la somme de 4 carrés:
Cependant, il est beaucoup trop lent pour d'autres sommes.
la source
IntegerPartitions
. Comme vous pouvez le voir sur les timings, la vitesse varie considérablement selon que le premier (le plus grand) nombre est proche de la racine carrée den
. Merci d'avoir rattrapé la violation des spécifications dans la version précédente.f[805306368]
? Sans diviser par les puissances de 4 en premier, ma solution prend 0,05 s pour 999999999; J'ai abandonné la référence pour 805306368 après 5 minutes ...f[805306368]
revient{16384, 16384, 16384}
après 21 minutes. J'ai utilisé {3} à la place de {4}. La tentative de résolution avec une somme de 4 carrés non nuls a échoué après plusieurs heures de fonctionnement.IntegerPartitions[n,4,Range[Floor@Sqrt@n]^2
devrait aussi fonctionner. Cependant, je ne pense pas que vous devriez utiliser la méthode 1 pour votre score, car elle ne respecte pas le délai spécifié dans la question.Perl -
116 octets87 octets (voir la mise à jour ci-dessous)En comptant le shebang comme un octet, des nouvelles lignes ont été ajoutées pour une raison horizontale.
Quelque chose d'une combinaison de code-golf - soumission de code le plus rapide .
La complexité moyenne (pire?) Des cas semble être
O (log n)O (n 0,07 ) . Rien de ce que j'ai trouvé ne tourne plus lentement que 0,001 s, et j'ai vérifié toute la plage de 900000000 à 999999999 . Si vous trouvez quelque chose qui prend beaucoup plus de temps que cela, ~ 0,1 s ou plus, faites-le moi savoir.Exemple d'utilisation
Les deux derniers semblent être les scénarios les plus défavorables pour les autres soumissions. Dans les deux cas, la solution présentée est littéralement la toute première chose vérifiée. Car
123456789
c'est le second.Si vous souhaitez tester une plage de valeurs, vous pouvez utiliser le script suivant:
Meilleur lorsqu'il est redirigé vers un fichier. La plage
1..1000000
prend environ 14 secondes sur mon ordinateur (71000 valeurs par seconde) et la plage999000000..1000000000
prend environ 20 secondes (50000 valeurs par seconde), conformément à la complexité moyenne O (log n) .Mise à jour
Edit : Il s'avère que cet algorithme est très similaire à celui qui a été utilisé par les calculatrices mentales pendant au moins un siècle .
Depuis la publication initiale, j'ai vérifié chaque valeur sur la plage de 1 à 1000000000 . Le comportement du «pire des cas» a été démontré par la valeur 699731569 , qui a testé un grand total de 190 combinaisons avant d'arriver à une solution. Si vous considérez 190 comme une petite constante - et je le fais certainement - le pire des cas sur la plage requise peut être considéré comme O (1) . Autrement dit, aussi rapide que la recherche de la solution à partir d'une table géante, et en moyenne, peut-être plus rapidement.
Une autre chose cependant. Après 190 itérations, rien de plus grand que 144400 n'a même dépassé le premier passage. La logique de la traversée en largeur est sans valeur - elle n'est même pas utilisée. Le code ci-dessus peut être raccourci un peu:
Qui n'effectue que la première passe de la recherche. Nous devons cependant confirmer qu'aucune valeur inférieure à 144400 n'a nécessité la deuxième passe:
En bref, pour la gamme 1..1000000000 , une solution à temps quasi constant existe, et vous la regardez.
Mise à jour mise à jour
@Dennis et moi avons apporté plusieurs améliorations à cet algorithme. Vous pouvez suivre les progrès dans les commentaires ci-dessous, et la discussion ultérieure, si cela vous intéresse. Le nombre moyen d'itérations pour la plage requise est passé d'un peu plus de 4 à 1,229 , et le temps nécessaire pour tester toutes les valeurs pour 1..1000000000 a été amélioré de 18 m 54 s à 2 m 41 s. Le pire des cas nécessitait auparavant 190 itérations; le pire des cas maintenant, 854382778 , n'a besoin que de 21 .
Le code Python final est le suivant:
Celui-ci utilise deux tables de correction pré-calculées, l'une de 10 Ko, l'autre de 253 Ko. Le code ci-dessus inclut les fonctions de générateur pour ces tables, bien qu'elles devraient probablement être calculées au moment de la compilation.
Une version avec des tables de correction de taille plus modeste peut être trouvée ici: http://codepad.org/1ebJC2OV Cette version nécessite une moyenne de 1.620 itérations par terme, avec le pire des cas de 38 , et toute la gamme fonctionne en environ 3m 21s. Un peu de temps est compensé, en utilisant au niveau du bit
and
pour la correction b , plutôt que modulo.Améliorations
Les valeurs paires sont plus susceptibles de produire une solution que les valeurs impaires.
L'article de calcul mental lié à précédemment note que si, après avoir supprimé tous les facteurs de quatre, la valeur à décomposer est paire, cette valeur peut être divisée par deux, et la solution reconstruite:
Bien que cela puisse être logique pour le calcul mental (les valeurs plus petites ont tendance à être plus faciles à calculer), cela n'a pas beaucoup de sens algorithmiquement. Si vous prenez 256 4 -tuples aléatoires et examinez la somme des carrés modulo 8 , vous constaterez que les valeurs 1 , 3 , 5 et 7 sont chacune atteintes en moyenne 32 fois. Cependant, les valeurs 2 et 6 sont chacune atteintes 48 fois. La multiplication des valeurs impaires par 2 trouvera une solution, en moyenne, dans 33% d' itérations en moins. La reconstruction est la suivante:
Il faut veiller à ce que a et b aient la même parité, ainsi que c et d , mais si une solution a été trouvée, un bon ordre est garanti d'exister.
Les chemins impossibles n'ont pas besoin d'être vérifiés.
Après avoir sélectionné la deuxième valeur, b , il peut déjà être impossible pour une solution d'exister, étant donné les résidus quadratiques possibles pour un modulo donné. Au lieu de vérifier de toute façon ou de passer à l'itération suivante, la valeur de b peut être «corrigée» en la décrémentant de la plus petite quantité qui pourrait éventuellement conduire à une solution. Les deux tables de correction stockent ces valeurs, l'une pour b et l'autre pour c . L'utilisation d'un modulo plus élevé (plus précisément, l'utilisation d'un modulo avec relativement moins de résidus quadratiques) se traduira par une meilleure amélioration. La valeur a n'a besoin d'aucune correction; en modifiant n pour qu'il soit pair, toutes les valeurs dea sont valides.
la source
Python 3 (177)
Après avoir réduit l'entrée
N
pour qu'elle ne soit pas divisible par 4, elle doit être exprimable sous la forme d'une somme de quatre carrés où l'un d'eux est soit la plus grande valeur possible,a=int(N**0.5)
soit un de moins que cela, ne laissant qu'un petit reste pour la somme des trois autres carrés prendre soin de. Cela réduit considérablement l'espace de recherche.Voici une preuve plus tard ce code trouve toujours une solution. Nous souhaitons trouver une
a
sorte quin-a^2
soit la somme de trois carrés. D'après le théorème des trois carrés de Legendre , un nombre est la somme de trois carrés, sauf s'il s'agit de la forme4^j(8*k+7)
. En particulier, ces nombres sont soit 0 soit 3 (modulo 4).Nous montrons que deux consécutifs
a
peuvent faire la quantité de restesN-a^2
ont une telle forme pour les deux valeurs consécutives .. Nous pouvons le faire en faisant simplement une table dea
etN
modulo 4, notant queN%4!=0
parce que nous avons extrait tous les pouvoirs de 4 surN
.Parce que pas deux années consécutives
a
donner(N-a*a)%4 in [0,3]
, l' un d'entre eux est sûr à utiliser. Donc, nous utilisons avidement le plus grand possiblen
avecn^2<=N
, etn-1
. DepuisN<(n+1)^2
, le resteN-a^2
à représenter comme une somme de trois carrés est au plus(n+1)^2 -(n-1)^2
, ce qui équivaut4*n
. Il suffit donc de vérifier uniquement les valeurs jusqu'à2*sqrt(n)
, ce qui correspond exactement à la plageR
.On pourrait encore optimiser le temps d'exécution en s'arrêtant après une seule solution, en calculant plutôt qu'en itérant pour la dernière valeur
d
et en recherchant uniquement parmi les valeursb<=c<=d
. Mais, même sans ces optimisations, le pire cas que j'ai pu trouver s'est terminé en 45 secondes sur ma machine.La chaîne "for x in R" est regrettable. Il peut probablement être raccourci par substitution ou remplacement de chaîne en itérant sur un seul index qui code (a, b, c, d). L'importation d'itertools s'est avérée inutile.
Edit: Changé à
int(2*n**.5)+1
partir2*int(n**.5)+2
de faire plus propre argument, même nombre de caractères.la source
5 => (2, 1, 0, 0)
5 => (2, 1, 0, 0)
lance sur Ideone 3.2.3 ou dans Idle 3.2.2. Qu'est ce que tu obtiens?5 => (2, 1, 0, 0)
. Avez-vous même lu le commentaire? (Maintenant, nous avons 3 commentaires d'affilée qui ont cet extrait de code. Pouvons-nous continuer la séquence?)5 => (2, 1, 0, 0)
, cela signifie2^2 + 1^2 + 0^2 + 0^2 = 5
. Alors oui, nous le pouvons.5 => (2, 1, 0, 0)
c'est correct. Les exemples de la question considèrent 0 ^ 2 = 0 comme un nombre carré valide. J'ai donc interprété (comme je pense que xnor l'a fait) que British Color avait quelque chose d'autre. La couleur britannique, comme vous ne l'avez pas encore répondu, pouvons-nous supposer que vous l'avez effectivement2,1,0,0
?CJam ,
91907471 octetsCompact, mais plus lent que mon autre approche.
Essayez-le en ligne! Collez le code , saisissez l'entier souhaité dans Entrée et cliquez sur Exécuter .
Contexte
Ce message a commencé comme une réponse GolfScript de 99 octets . Bien qu'il y ait encore place à amélioration, GolfScript manque de fonction sqrt intégrée. J'ai gardé la version GolfScript jusqu'à la révision 5 , car elle était très similaire à la version CJam.
Cependant, les optimisations depuis la révision 6 nécessitent des opérateurs qui ne sont pas disponibles dans GolfScript, donc au lieu de publier des explications distinctes pour les deux langues, j'ai décidé d'abandonner la version moins compétitive (et beaucoup plus lente).
L'algorithme implémenté calcule les nombres par force brute:
Pour l'entrée
m
, trouverN
etW
tel quem = 4**W * N
.Set
i = 257**2 * floor(sqrt(N/4))
.Set
i = i + 1
.Trouvez des entiers
j, k, l
tels quei = 257**2 * j + 257 * k + l
, oùk, l < 257
.Vérifiez si
d = N - j**2 - k**2 - l**2
c'est un carré parfait.Si ce n'est pas le cas, et revenez à l'étape 3.
Imprimer
2**W * j, 2**W * k, 2**W * l, 2**W * sqrt(m)
.Exemples
Les horaires correspondent à un Intel Core i7-4700MQ.
Comment ça fonctionne
la source
C, 228
Ceci est basé sur l'algorithme de la page Wikipedia, qui est une force brute O (n).
la source
GolfScript,
133130129 octetsRapide, mais long. La nouvelle ligne peut être supprimée.
Essayez-le en ligne. Notez que l'interprète en ligne a un délai de 5 secondes, il peut donc ne pas fonctionner pour tous les numéros.
Contexte
L'algorithme tire parti du théorème de Legendre à trois carrés , qui stipule que tout nombre naturel n qui n'est pas de la forme
peut être exprimée comme la somme de trois carrés.
L'algorithme fait ce qui suit:
Exprimez le nombre comme
4**i * j
.Trouvez le plus grand entier
k
tel quek**2 <= j
etj - k**2
vérifie l'hypothèse du théorème de Legendre à trois carrés.Set
i = 0
.Vérifiez si
j - k**2 - (i / 252)**2 - (i % 252)**2
c'est un carré parfait.Si ce n'est pas le cas, incrémentez
i
et revenez à l'étape 4.Exemples
Les horaires correspondent à un Intel Core i7-4700MQ.
Comment ça fonctionne
la source
j-k-(i/252)-(i%252)
. D'après vos commentaires (je ne peux pas lire le code), il semble que vous vouliez direj-k-(i/252)^2-(i%252)^2
. BTW, l'équivalent dej-k-(i/r)^2-(i%r)^2
où r = sqrt (k) peut enregistrer quelques caractères (et semble fonctionner sans problème même pour k = 0 dans mon programme C.)j-k^2-(i/252)^2-(i%252)^2
. J'attends toujours que l'OP clarifie si 0 est une entrée valide ou non. Votre programme donne son1414 -nan 6 4.000000
avis0
.0/
=> crash! : P J'ai exécuté votre version 1 sur mon ordinateur portable (i7-4700MQ, 8 Go de RAM). En moyenne, le temps d'exécution est de 18,5 secondes.Rév.1: C, 190
C'est encore plus de mémoire que rev 0. Même principe: construisez une table avec une valeur positive pour toutes les sommes possibles de 2 carrés (et zéro pour les nombres qui ne sont pas des sommes de deux carrés), puis recherchez-la.
Dans cette version, utilisez un tableau de
short
au lieu dechar
pour stocker les résultats, afin que je puisse stocker la racine de l'une des paires de carrés dans la table au lieu d'un simple indicateur. Cela simplifie considérablement la fonctionp
(pour décoder la somme de 2 carrés) car il n'y a pas besoin de boucle.Windows a une limite de 2 Go sur les tableaux. Je peux contourner ce
short s[15<<26]
qui est un tableau de 1006632960 éléments, assez pour se conformer aux spécifications. Malheureusement, la taille totale d'exécution du programme est toujours supérieure à 2 Go et (malgré des ajustements des paramètres du système d'exploitation), je n'ai pas pu exécuter cette taille (bien que cela soit théoriquement possible.) Le mieux que je puisse faire estshort s[14<<26]
(939524096 éléments.)m*m
Doit être strictement inférieur à cela (30651 ^ 2 = 939483801.) Néanmoins, le programme fonctionne parfaitement et devrait fonctionner sur tout système d'exploitation qui n'a pas cette restriction.Code non golfé
Rév 0 C, 219
Ceci est une bête affamée de mémoire. Il prend un tableau de 1 Go, calcule toutes les sommes possibles de 2 carrés et stocke un indicateur pour chacun dans le tableau. Ensuite, pour l'entrée utilisateur z, il recherche dans le tableau deux sommes de 2 carrés a et za.
la fonction
p
reconstitue ensuite les carrés originaux qui ont été utilisés pour faire les sommes de 2 carrésa
et lesz-a
imprime, le premier de chaque paire sous forme d'entier, le second sous forme de double (s'il doit s'agir de tous les entiers, deux caractères supplémentaires sont nécessaires,t
>m=t
.)Le programme prend quelques minutes pour construire le tableau des sommes des carrés (je pense que cela est dû à des problèmes de gestion de la mémoire, je vois l'allocation de mémoire augmenter lentement au lieu de sauter comme on pourrait s'y attendre.) Cependant, une fois cela fait, produit des réponses très rapidement (si plusieurs nombres doivent être calculés, le programme à
scanf
partir de maintenant peut être mis en boucle.code non golfé
Exemple de sortie
Le premier est par la question. Le second a été choisi comme difficile à rechercher. Dans ce cas, le programme doit rechercher jusqu'à 8192 ^ 2 + 8192 ^ 2 = 134217728, mais ne prend que quelques secondes une fois la table créée.
la source
#include <stdio.h>
(pour scanf / printf) ou#include <math.h>
(pour sqrt.) Le compilateur relie automatiquement les bibliothèques nécessaires. Je dois remercier Dennis pour cela (il m'a dit sur cette question codegolf.stackexchange.com/a/26330/15599 ) Le meilleur conseil de golf que j'ai jamais eu.include
. Pour compiler sous Linux, vous avez besoin du drapeau-lm
stdio
et plusieurs autres bibliothèques, mais pasmath
même avec leinclude
? Par lequel je comprends que si vous mettez le drapeau du compilateur, vous n'en avez pas besoin deinclude
toute façon? Eh bien, cela fonctionne pour moi, donc je ne me plains pas, merci encore pour le conseil. BTW J'espère publier une réponse complètement différente en profitant du théorème de Legendre (mais il utilisera toujours asqrt
.)-lm
affecte l'éditeur de liens, pas le compilateur.gcc
choisit de ne pas avoir besoin des prototypes pour les fonctions qu'il "connaît", il fonctionne donc avec ou sans les inclusions. Cependant, les fichiers d'en-tête ne fournissent que des prototypes de fonctions, pas les fonctions elles-mêmes. Sous Linux (mais pas Windows, apparemment), la bibliothèque mathématique libm ne fait pas partie des bibliothèques standard, vous devez donc demanderld
à vous y connecter.Mathematica, 138 caractèresIl s'avère donc que cela produit des résultats négatifs et imaginaires pour certaines entrées comme indiqué par edc65 (par exemple, 805306368), donc ce n'est pas une solution valide. Je vais le laisser pour l'instant, et peut-être, si je déteste vraiment mon temps, je vais y retourner et essayer de le réparer.
Ou, sans tremblement:
Je n'ai pas trop regardé les algorithmes, mais je pense que c'est la même idée. Je viens juste de trouver la solution évidente et je l'ai modifiée jusqu'à ce qu'elle fonctionne. Je l'ai testé pour tous les nombres entre 1 et un milliard et ... ça marche. Le test ne prend qu'environ 100 secondes sur ma machine.
Le bon côté à ce sujet est que, puisque b, c et d sont définis avec des affectations retardées
:=
, ils n'ont pas besoin d'être redéfinis lorsque a est décrémenté. Cela a sauvé quelques lignes supplémentaires que j'avais auparavant. Je pourrais le jouer plus loin et imbriquer les parties redondantes, mais voici le premier projet.Oh, et vous l'exécutez en tant que
S@123456789
et vous pouvez le tester avec{S@#, Total[(S@#)^2]} & @ 123456789
ou# == Total[(S@#)^2]&[123456789]
. Le test exhaustif estJ'ai utilisé une instruction Print [] auparavant, mais cela l'a beaucoup ralentie, même si elle n'est jamais appelée. Allez comprendre.
la source
n - a^2 - b^2 - c^2
tant que variable et de vérifier qued^2
cela est égal.a * 4^(2^k)
pourk>=2
, ayant extrait toutes les puissances de 4, cea
n'est donc pas un multiple de 4 (mais pourrait être pair). De plus, chacuna
est soit 3 mod 4, soit deux fois un tel nombre. Le plus petit est 192.Haskell 123 + 3 = 126
Force brute simple sur des carrés pré-calculés.
Il a besoin de l'
-O
option de compilation (j'ai ajouté 3 caractères pour cela). Cela prend moins d'une minute pour le pire des cas 999950883.Testé uniquement sur GHC.
la source
C: 198 caractèresJe peux probablement le réduire à un peu plus de 100 caractères. Ce que j'aime dans cette solution, c'est la quantité minimale d'ordure, juste une simple boucle for, faisant ce qu'une boucle for devrait faire (ce qui est fou).
Et fortement embelli:
Edit: Ce n'est pas assez rapide pour toutes les entrées, mais je reviendrai avec une autre solution. Je vais laisser ce désordre d'opération ternaire rester à partir de maintenant.
la source
Rév B: C, 179
Merci à @Dennis pour les améliorations. Le reste de la réponse ci-dessous n'est pas mis à jour à partir de la rév. A.
Rév A: C, 195
Beaucoup plus rapide que mon autre réponse et avec beaucoup moins de mémoire!
Cela utilise http://en.wikipedia.org/wiki/Legendre%27s_three-square_theorem . Tout nombre non de la forme suivante peut être exprimé comme la somme de 3 carrés (j'appelle cela la forme interdite):
4^a*(8b+7), or equivalently 4^a*(8b-1)
Notez que tous les nombres carrés impairs sont de la forme
(8b+1)
et tous les nombres carrés pairs sont superficiellement de la forme4b
. Cependant, cela masque le fait que tous les nombres pairs sont de la forme4^a*(odd square)==4^a*(8b+1)
. Par conséquent,2^x-(any square number < 2^(x-1))
pour impairx
sera toujours de la forme interdite. Par conséquent, ces nombres et leurs multiples sont des cas difficiles, c'est pourquoi tant de programmes ici divisent les puissances de 4 dans un premier temps.Comme indiqué dans la réponse de @ xnor,
N-a*a
ne peut pas être de la forme interdite pour 2 valeurs consécutives dea
. Ci-dessous, je présente une forme simplifiée de son tableau. En plus du fait qu'après division par 4N%4
ne peut pas être égal à 0, notez qu'il n'y a que 2 valeurs possibles pour(a*a)%4
.Donc, nous voulons éviter que les valeurs de
(N-a*a)
cela puissent être de la forme interdite, à savoir celles où(N-a*a)%4
est 3 ou 0. Comme on peut le voir, cela ne peut pas se produire pour la même choseN
à la fois impaire et pair(a*a)
.Donc, mon algorithme fonctionne comme ceci:
J'aime particulièrement la façon dont je fais l'étape 3. J'ajoute 3 à
N
, de sorte que le décrément est requis si(3+N-a*a)%4 =
3 ou 2. (mais pas 1 ou 0.) Divisez cela par 2 et le travail peut être fait par une expression assez simple .Code non golfé
Notez la seule
for
boucleq
et l' utilisation de la division / modulo pour dériver les valeurs deb
etc
de lui. J'ai essayé d'utilisera
comme diviseur au lieu de 256 pour économiser des octets, mais parfois la valeur dea
n'était pas correcte et le programme se bloquait, peut-être indéfiniment. 256 était le meilleur compromis que je peux utiliser>>8
au lieu de/256
pour la division.Production
Une bizarrerie intéressante est que si vous entrez un nombre carré,
N-(a*a)
= 0. Mais le programme détecte que0%4
= 0 et diminue au carré suivant. En conséquence, les entrées de nombres carrés sont toujours décomposées en un groupe de carrés plus petits, sauf si elles sont de la forme4^x
.la source
m=1
avantmain
. 2. Exécutezscanf
dans l'for
instruction. 3. Utilisezfloat
au lieu dedouble
. 4.n%4<1
est plus court que!(n%4)
. 5. Il y a un espace obsolète dans la chaîne de format de printf.n-=a*a
ne fonctionne pas, cara
peut être modifié par la suite (il donne de mauvaises réponses et se bloque sur un petit nombre de cas, comme 100 + 7 = 107.) J'ai inclus tout le reste. Ce serait bien de raccourcir quelque choseprintf
mais je pense que la seule réponse est de changer la langue. La clé de la vitesse est de s'installera
rapidement sur une bonne valeur . Écrit en C et avec un espace de recherche inférieur à 256 ^ 2, c'est probablement le programme le plus rapide ici.printf
instruction semble difficile sans utiliser une macro ou un tableau, ce qui ajouterait du volume ailleurs. Changer de langue semble être le moyen "facile". Votre approche pèserait 82 octets en CJam.JavaScript -
175191176173 caractèresForce brute, mais rapide.
Édition rapide mais pas suffisante pour une entrée désagréable. J'ai dû ajouter une première étape de réduction par multiplications de 4.
Edit 2 Débarrassez-vous de la fonction, sortez dans la boucle puis forcez la sortie
Modifier 3 0 n'est pas une entrée valide
Non golfé:
Exemple de sortie
la source