Mark vit dans un petit pays peuplé de gens qui ont tendance à trop penser aux choses. Un jour, le roi du pays décide de repenser la monnaie du pays pour rendre le changement plus efficace. Le roi veut minimiser le nombre de pièces attendu pour payer exactement tout montant jusqu'à (mais sans inclure) le montant de la plus petite facture papier.
Supposons que la plus petite unité monétaire soit la pièce. La plus petite facture papier du royaume vaut pièces. Le roi décide qu'il ne doit pas y avoir plus de différentes dénominations de pièces en circulation. Le problème est donc de trouver un set \ {d_1, d_2, ..., d_m \} d'entiers de \ {1, 2, ..., n - 1 \} qui minimise \ frac {1} {n-1} \ sum_ {i = 1} ^ {n-1} {c_1 (i) + c_2 (i) + ... + c_m (i)} sous réserve de c_1 (i) d_1 + c_2 (i) d_2 + ... c_m (i) d_m = i .
Par exemple, prenez l'USD standard et ses dénominations de pièces de . Ici, la plus petite facture papier vaut 100 de la plus petite pièce. Il faut 4 pièces pour faire 46 cents en utilisant cette monnaie; nous avons . Cependant, si nous avions des pièces de , il ne faudrait que 3 pièces: . Lequel de ces ensembles de coupures minimise le nombre moyen de pièces pour faire une somme allant jusqu'à 99 cents inclus?
Plus généralement, étant donné et , comment pourrait-on déterminer algorithmiquement l'ensemble optimal? De toute évidence, on pourrait énumérer tous les sous-ensembles viables et calculer le nombre moyen de pièces nécessaires pour faire des sommes de 1 à , en gardant une trace optimale en cours de route. Puisqu'il y a environ (qui ne sont pas tous viables, mais quand même), cela ne serait pas terriblement efficace. Pouvez-vous faire mieux que ça?
la source
Réponses:
Ceci est lié au problème bien connu du changement . En fait, si bien étudié, que cette question a été étudiée pour [1] en utilisant la force brute. Depuis 2003, la difficulté de trouver des dénominations optimales semble être un problème ouvert.m ≤ 7
Si vous consultez les articles citant Shallit, il semble que les dénominations permettant des stratégies de changement gourmandes étaient d'un intérêt particulier. Il est clair que ces dénominations présentent des avantages dans la pratique.
la source
J'ai deviné (à tort, mais supportez-moi) que la série de pièces serait optimale, car les pièces seraient espacées de façon exponentielle, réduisant ainsi la valeur restante autant que possible par pièce ajoutée. Pour votre exemple, ce serait .{bje| b=⌈ n1 / m⌉ , 0 ≤ i < m } { 1 , 3 , 9 , 27 , 81 }
C'est un cran meilleur ( ) que les coupures en USD ( ), mais cela ne veut rien dire.390 / 99 420 / 99
J'ai écrit un script Haskell hack pour obtenir des chiffres par force brute, car je ne sais pas comment aborder cela analytiquement.( m , n ) = ( 4 , 30 ) 75 / 29 { 20 , 8 , 3 , 1 } 87 / 29 { 27 , 9 , 3 , 1 } ( 5 , 100 )
Il s'avère que la distribution exponentielle n'est pas toujours la meilleure: il y en a parfois un peu mieux, par exemple pour on obtient pour mais pour . Ma machine lente ne peut pas atteindre , nous devons donc utiliser des nombres plus petits, ici.
Cependant, j'ai remarqué que l'erreur semble être assez petite. La plupart du temps, la division des sommes donne quelque chose commençant par un 1.0 ..., j'ai donc effectué quelques tests supplémentaires.
À partir d'un ensemble de tests avec et , nous obtenons une erreur moyenne de notre croissance exponentielle par rapport à la meilleure solution de avec un écart-type de .3 ≤ m ≤ 5 6 ≤ n ≤ 40 1.12 0,085
Vous pourriez faire valoir que les paramètres de test sont plutôt petits, mais comme vous le faites remarquer, c'est juste beaucoup de force brute si vous définissez (il y a très probablement une meilleure solution, mais c'était une excellente excuse pour se relâcher et faire quelques Haskell).n = 100
Voici ma suite de tests, si vous voulez l'essayer:
J'ai fait le test avec
la source