Un moment de retour dans une compétition de programmation, j'ai rencontré un problème déroutant, et cela m'a dérangé depuis. Bien que je ne me souvienne pas de cela, je ferai de mon mieux pour le reproduire: p>
Jack commence à 0 sur la ligne de numéro et saute une unité dans les deux sens. Chaque saut successif qu'il fait est plus long que la précédente par une unité et peut être faite dans les deux sens. Écrivez un programme qui prend un numéro et renvoie le nombre minimum de sauts Jack pour atteindre ce numéro. P> blockQuote>
Je m'excuse à l'avance si cela n'est pas considéré comme une bonne question, ni si le titre est jugé trompeur. P>
6 Réponses :
Vous pouvez modéliser les progrès de Jack comme un arbre binaire, où le nœud gauche représente un saut en arrière, et le nœud droit représente un saut en avant.
La valeur de chaque noeud est la position actuelle de la prise. P>
La profondeur du nœud correspond à la longueur de saut actuelle. P>
aussi, l'ensemble du sous-arbre de gauche inférieur à la racine peut Être taillé, car toutes les valeurs sont la négation des valeurs correspondantes dans le sous-arbre de droite. Par exemple: P> Sous-arbre à droite:
0 + 1 + 2 + 3 - 4 = 2 P> image miroir dans la sous-arbre gauche:
0 - 1 - 2 - 3 + 4 = -2 P> Heureusement, il semble que l'arbre génère de nombreux duplicats. Par exemple, à la profondeur = 7, au lieu de 32 nœuds (64/2, car nous ne traitons que du sous-arbre à droite), il semble que 6 nœuds distincts: P> 4 = 0 + 1 + 2 + 3 + 4 - 5 + 6 - 7
14 = 0 + 1 + 2 + 3 + 4 + 5 + 6 - 7
16 = 0 + 1 + 2 + 3 + 4 + 5 - 6 + 7
18 = 0 + 1 + 2 + 3 + 4 - 5 + 6 + 7
20 = 0 + 1 + 2 + 3 - 4 + 5 + 6 + 7
28 = 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7
Pourquoi votre table ne liste-t-elle pas zéro, ni 2, 6, 8, 10, 12, 14, 22, 24 ou 26?
@supercat, je pensais mal à tort que vous pourriez pruneaux de nœuds qui étaient un duplicata de nœuds supérieurs - voir mon édition.
Hmmm ... qui semble fonctionnerait, mais le temps de fonctionnement ne serait-il pas quelque chose comme o (2 ^ n)? (où n est la réponse)
@Lorkenpeist - Correct. SuperCat a fourni la meilleure solution.
Pour tout nombre de sauts, on peut facilement calculer la distance maximale positive que la prise pourrait voyager. Abandonner la polarité des sauts positifs totalisant toute valeur particulière K EM> entraînera la fin de la prise de 2 000 comptes ci-dessous où elle aurait autrement. Pour toute distance maximale t em> et tout non négatif n em> de la même parité (même si t em> est même; impair si t em> est impair) inférieur ou égal à cette distance, il sera possible de trouver une combinaison de sauts qui totalement n em>. Ainsi, il n'est donc pas nécessaire de ne pas vous inquiéter d'arbres, de sacs à dos ou d'autres choses telles que de tels sauts seront suffisants et si cela donnera la "parité" correcte. P>
Pouvez-vous donner un exemple? Par exemple, pourriez-vous passer à travers le calcul du nombre de sauts à atteindre 12?
Quatre sauts pourraient atteindre un maximum de dix (même, mais trop petit). Cinq sauts pourraient atteindre un maximum de 15 (impair). Six sauts 21 (aussi impair). Sept sauts 28 (même et assez grand). 1 + 2-3 + 4-5 + 6 + 7 = 1 + 2 + + 4 + 6 + 7 - 3-5 = 12.
Merci - je l'obtiens maintenant. Très bonne réponse!
Très intelligent, je n'aurais jamais pensé à cela.
Belle réponse, @supercat, vote. Si vous pouviez élaborer un peu plus, que voulez-vous dire "à basculer la polarité des sauts positifs totalisant une valeur particulière k ferrera la fin de la prise de 2 000 comptes ci-dessous où elle aurait autrement" par exemple, ce sera génial.
La formule de la somme des entiers consécutifs ou p> la "version" négative donnera toujours un numéro imaginaire, qui n'est pas pertinent ici, donc nous avons p> Prenez le plafond de ce numéro et vous avez le nombre initial de sauts nécessaires. p> Overshoot est un peu compliqué. Dans notre exemple Pour 12 donc, nous essayons n (n + 1) / 2 code>. Par exemple,
1 + 2 + 3 + 4 = 10 code> =
4 * 5/2 = 10 code>. Il s'agit du nombre minimum d'étapes nécessaires pour atteindre le numéro cible. Mais il pourrait y avoir une dépassement. Dites que la cible est
11 code>. Quatre sauts vous obtiendront à
10 code> (nous venons de calculer que), mais
5 code> vous permettra d'obtenir
5 * 6/2 = 15 code>. Maintenant, nous notons uniquement que dans le cas de 11, nous sautons en arrière lorsque la taille de l'étape est
2 code>, et nous arrivons à
11 code> correctement. Nous traiterons plus de détails avec dépassement plus de détails. Retour à la façon de calculer le nombre de sauts en premier lieu. Notre formule est
n (n + 1) / 2 = x code> où
x code> est le numéro cible. Le L'équation quadratique nous dit que la solution à ceci est
11 code> exemple, le dépassement est
4 code> (
15-11 = 4 code>), donc nous avons juste besoin de faire le
+2 code> saut en
-2 code> saut, et qui est le lieu de "planque" la remise des gaz 4. Cependant, les choses ne sont pas toujours aussi simples:
12 code> est accessible via
-1-2 + 3 + 4-5 + 6 + 7 code>: il nécessite
7 < / code> étapes, pas
5 code> comme prévu. L'observation de base est qu'une dépassement doit être
12 code> p>
5 code>, qui nous amène à
15 code> li>
3 code>. li>
5 code> étapes, ce qui donne
15 code> et dépassement de
3 code>. Ensuite, nous essayons six étapes produisant
21 code> et un dépassement de
9 code>. Enfin, nous essayons
7 code> Étapes générant
28 code> et un dépassement de
16 code>. Ceci est notre nombre minimum d'étapes. Cela peut probablement être calculé par une formule, cependant. P> p>
Le problème est le suivant:
Rechercher le plus petit Nous avons un système d'équations: p> Il y a trois inconnues et seulement deux équations. Nous pouvons combiner pour obtenir une équation ciblée pour satisfaire: P> Nous devons trouver le plus petit «code> k code> k code> tel que cette solution puisse être satisfaite pour l'entier Ceci gère la partie sur tous les nombres étant entiers. Pour gérer la pièce sur ouf. Maintenant, pour un exemple: p> dire que n = 7. Ensuite, nous ne connaissons pas non plus k code> pour laquelle la somme du premier
k code> naturel positif tel que k (k + 1) / 2 = A + B $, où $ n = A - B $. P>
k (k + 1) / 2 = a + b code> li>
n = A - B CODE> LI>
a, b, k code> sont des entiers positifs li>
ul>
n code>, étant donné que
a code> doit être un entier positif. Notons quelques choses: p>
n code> est même, puis
k code> ou
k + 1 code> doit être divisible par 4; I.e.,
k = 0 ou 3 mod 4 code>. li>
n code> est impair, alors ni
k code> ni
k + 1 code> peut être divisible par 4; I.e.,
k = 1 ou 2 mod 4 code>. li>
ol>
k code> et
A code> étant positif, nous devons stipuler que p>
k> = plancher (sqrt (2n)) code> li>
ul>
k code> k + 1 code> sont divisibles par 4. De même, nous Sachez que
k> = 4 code>. Nous pouvons ignorer immédiatement
k = 4 code> car nous savons
k code> n'est pas divisible par 4. Nous pouvons essayer
k = 5 code>; Nous entrons dans notre système: p>
----------J------N---
---------J-------N--- -1
-----------J-----N--- +2
--------J--------N--- -3
------------J----N--- +4
-----------------J--- +5
Nous recherchons le montant des numéros nécessaires pour que la somme de 1 à J soit plus grande que le numéro cible et de la même parité.
Voici un code de travail simple à Python 2.7: P>
def numberOfJumps(n): n = abs(n) j = 0 while True: s = j*(j+1)/2 if s >= n and not (s - n)%2: break j += 1 return j for i in range(10): print i, numberOfJumps(i)
Je voudrais élaborer sur @ solution correcte et rapide de supercat et décrire un algorithme qui calcule une somme de longueur minimale en plus de calculer la longueur d'une telle somme. P>
Trouver le plus petit entier k tel que t_k: = 1 + 2 + 3 + ... + k> = | n | et t_k a la même parité que | n |. Ensuite, retourner les signes des summands de t_k de manière systématique au total n. p>
Voici les détails. Notez que t_k = k (k + 1) / 2, un nombre triangulaire. Réglage t_k = | n | et la résolution de k donne le plafond (-1 + sqrt (1 + 8 | n |)) / 2. Alors k est égal au plafond ou 1 ou 2 plus il, selon ces trois chiffres a la même parité que n et est moins. Ici nous utilisons le fait que l'ensemble {t, t + s, t + s + (s + 1)} de trois nombres triangulaires consécutifs contient les nombres pairs et impairs pour tous entiers positifs t, s. (Il suffit de cocher les quatre possibilités de parité pour t et s.) P>
Pour une somme de longueur minimale pour n, on calcule d'abord d: = (t_k - n) / 2. Parce que t_k> = | n | et t_k et n ont la même parité, d se situe dans l'ensemble {0, 1, 2, ..., t_k}. Maintenant soustraire à plusieurs reprises: d = A_K (k) + r_k, r_k = a_ {k-1} (k-1) + r_ {k-1}, ..., r_2 = A_1 (1) + r_1, en choisissant chaque a_i au maximum dans {0, 1}. Par le lemme ci-dessous, r_1 = 0. Alors d = {sum_ i = 1} ^ k i a i. Ainsi, n = t_k - 2d = sum_ {i = 1} ^ ki - sum_ {i = 1} ^ k i = 2a_i sum_ {i = 1} ^ k (1 - 2a_i i) et 1 - 2a_i réside dans {-1 , 1}. Donc, la séquence b_i:. = 1 - 2a_i est un chemin, et par la minimalité de k, b_i est un chemin minimal p>
Considérons le nombre cible n = 12. Selon l'algorithme 3, les possibilités de k sont de 5, 6 ou 7. Les valeurs correspondantes de t_k sont de 15, 21 et 28. Etant donné que 28 est le dernier de ceux-ci avec la même parité que n, on voit que k = 7 . Donc, d = (t_k - n) / 2 = 8, que nous écrivons 1 + 7 conformément à l'algorithme. Ainsi, un chemin d'accès le plus court est 12 + 2 + -1 3 + 4 + 5 + 6 -. 7 p>
Je dis a em> chemin le plus court, car les chemins les plus courts ne sont pas uniques en général.
Par exemple, 1 + 2 + 4 -3 -. 5 + 6 + 7 fonctionne également p>
Lemme: Soit A_K = {0, 1, 2, ..., t_k}.
Puis un mensonge numéro dans A_K si et seulement si elle peut être exprimée comme une somme sum_ {i = 1} ^ k i a i pour certains a_i de séquence dans {0, 1}. P>
Preuve: Par induction sur k.
Tout d'abord, 0 = {sum_ i = 1} ^ 0 1, la somme vide.
Maintenant, supposons que le résultat est valable pour tous les k - 1> = 0 et supposons qu'un mensonge nombre d dans A_K.
soustraire à plusieurs reprises: d = A_K (k) + r_k, r_k = a_ {k-1} (k-1) + r_ {k-1}, ..., en choisissant chaque a_i = 0 ou 1 au maximum dans {0, 1 } et l'arrêt lorsque les premiers mensonges de r_j dans A_j pour certains j En supposant que des opérations arithmétiques sont constante de temps, il faut O (1) le temps de calcul de k n, et par conséquent la longueur d'un chemin minimal à n.
Ensuite, il prend O (k) le temps de trouver une somme de longueur minimale pour d, alors O (k) le temps d'utiliser cette somme pour produire une somme de longueur minimale pour n.
Alors O (k) = O (sqrt (n)) tout. P> correct algorithme h2>
complexité du temps algorithme h2>
+1. Mais pourquoi avez-vous besoin de tout cela? La cible est T, et le numéro triangulaire que vous avez trouvé est U, vous n'avez-vous pas juste besoin de retourner le signe de (U-T) / 2? BTW, la question ne demande que le nombre de sauts.
@Knoothe, non, envisagez notre exemple de course de t = 12. Ensuite, U = 28, k = 7, et (t - u) / 2 = 8> k. Donc, il n'y a pas 8 bits pour retourner. En ce qui concerne la question originale, Oh ouais, vous avez raison, il suffit de trouver la longueur du chemin minimal, qui est k. Pourtant, trouver un chemin minimal est une bonne question aussi :-)
Oui, j'ai compris qu'après avoir posté le commentaire. Merci!
@achechev, bonne réponse, vote! Je travaille sur le même casse-tête. Une question muette, que voulez-vous dire "nombre triangulaire" et pourquoi il est important que T_K a la même parité que celle-ci |? Apprécier pour plus de détails.
Une des meilleures réponses pour cette question
Mot correct serait "problème de sacs à dos"
en.wikipedia.org/wiki/knapsack_problem
Vraiment, qu'avez-vous eu jusqu'à présent? Travaillez à travers les premiers sauts avec un crayon et un papier, ou votre programme de calculateur préféré, et un modèle émerge.
OK ok ok? Si votre numéro de cible est 2 B>, vous obtenez à 3 B> OK?
@Dhruvpathak - Je ne suis pas sûr que si le knapack s'applique vraiment à cela, car l'ensemble de chiffres à travailler ne sont pas fixés à l'avance. Vous pouvez utiliser +1 ou -1, mais pas à la fois, +2 ou -2, mais pas à la fois, etc.
@angelatlarge Il me semble que vous devez avoir à atterrir sur le nombre exact, sinon cela serait assez facile.
@BloonSTOWERDefence: Nous supposons donc que certains chiffres sont inaccessibles (par exemple 2 B>)? Ou je manque quelque chose?
@angelatlarge: 2 = 0 + 1 + 2 + 3 - 4
Oh, à droite. Pour une raison quelconque, j'ai lu la question doublant la taille de saut, pas +1. Merci!
@BelatLarge: Une chose que vous manquez est que Jack puisse atteindre n'importe quel entier fini dans un nombre fini de sauts.
@HighperformCemark - Y a-t-il une preuve que vous pouvez créer un lien à cela? Semble certainement vrai.
@angelatlarge Vous pourriez atteindre 2 via [1, -2, 3]
@HighperformCemark - Nevermind, la réponse de SuperCat indique clairement pourquoi cela est vrai.