J'ai fait le programme Haskell (non golfé) suivant pour le défi de golf de code de calculer les premières valeurs de A229037 .
Voici ma solution proposée pour calculer la ème valeur:
a n | n<1 = 0
| n<3 = 1
| otherwise = head (goods n)
goods n = [x | x <- [1..], isGood x n]
isGood x n = and [ x - a(n-k) /= a(n-k) - a(n-k-k) || a(n-k-k) == 0 | k <- [1..n] ]
Notez que Haskell ne met pas en cache ni ne mémorise automatiquement ces valeurs.
La page OEIS pour la séquence donne le fait que , donc le pourrait être remplacé par , car l'algorithme n'atteindra jamais un supérieur à .[1..]
[1..(n+1)/2]
En essayant de compter les appels de fonction, j'ai dérivé la limite supérieure , le nombre d'appels de fonction que l'algorithme prend pour une entrée :
J'ai branché la formule finale dans Mathematica:
RSolve[{T[n] == 2*T[n - 1]*n*(n + 1), T[1] == 1}, T[n], n]
Et obtenu, après une petite simplification:
Le rapport moyen entre cela et le temps d'exécution du programme Haskell, pour est de et l'écart-type des ratios est d'environ . (Curieusement, le diagramme logarithmique des ratios semble être une ligne droite).
Les rapports avec la première ligne, définissant , ont une moyenne et un écart type de et , respectivement, mais son tracé saute beaucoup.
Comment puis-je obtenir une meilleure limite sur la complexité temporelle de cet algorithme?
Voici l'algorithme en C valide (moins les déclarations avancées), qui je crois est à peu près équivalent au code Haskell:
int a(int n){
if (n < 1) {
return 0;
} else if (n < 3) {
return 1;
} else {
return lowestValid(n);
}
}
int lowestValid(int n){
int possible = 1; // Without checking, we know that this will not exceed (n+1)/2
while (notGood(possible, n)) {
possible++;
}
return possible;
}
int notGood(int possible, int n){
int k = 1;
while (k <= n) {
if ( ((possible - a(n-k)) == (a(n-k) - a(n-2*k))) && (a(n-2*k) != 0) ) {
return 1;
} else {
k++;
}
}
return 0;
}
La version C prend environ 5 minutes pour calculer et la version Haskell prend environ la même chose pour .
Les premières fois des versions:
Haskell: [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0e-2,3.0e-2,9.0e-2,0.34,1.42,11.77,71.68,184.37,1815.91]
C: [2.0e-6, 1.0e-6, 1.0e-6, 2.0e-6, 1.0e-6, 6.0e-6, 0.00003,0.00027, 0.002209, 0.005127, 0.016665, 0.080549, 0.243611, 0.821537, 4.56265, 24.2044, 272.212]
la source
a
mémorisé? Vous pouvez obtenir de meilleures réponses (ou n'importe laquelle, vraiment!) Si vous incluez une version de pseudo-code qui expose autant de ce qui se passe réellement que nécessaire pour une analyse rigoureuse.Réponses:
Vous pouvez écrire votre récurrence comme
la source