La solution de ce problème a été donnée un million de fois sur Internet. Le problème est appelé le problème de changement de pièce . On peut trouver des solutions sur http://rosettacode.org/wiki/Count_the_coins et un modèle mathématique de celui-ci sur http://jaqm.ro/issues/volume-5,issue-2/pdfs/patterson_harmel.pdf (ou changement de pièce Google problème ).
Soit dit en passant, la solution Scala de Tsagadai est intéressante. Cet exemple produit 1 ou 0. Comme effet secondaire, il répertorie sur la console toutes les solutions possibles. Il affiche la solution, mais échoue à la rendre utilisable de quelque manière que ce soit.
Pour être le plus utile possible, le code doit renvoyer un List[List[Int]]
afin de permettre d'obtenir le nombre de solutions (longueur de la liste des listes), la "meilleure" solution (la liste la plus courte), ou toutes les solutions possibles.
Voici un exemple. C'est très inefficace, mais c'est facile à comprendre.
object Sum extends App {
def sumCombinations(total: Int, numbers: List[Int]): List[List[Int]] = {
def add(x: (Int, List[List[Int]]), y: (Int, List[List[Int]])): (Int, List[List[Int]]) = {
(x._1 + y._1, x._2 ::: y._2)
}
def sumCombinations(resultAcc: List[List[Int]], sumAcc: List[Int], total: Int, numbers: List[Int]): (Int, List[List[Int]]) = {
if (numbers.isEmpty || total < 0) {
(0, resultAcc)
} else if (total == 0) {
(1, sumAcc :: resultAcc)
} else {
add(sumCombinations(resultAcc, sumAcc, total, numbers.tail), sumCombinations(resultAcc, numbers.head :: sumAcc, total - numbers.head, numbers))
}
}
sumCombinations(Nil, Nil, total, numbers.sortWith(_ > _))._2
}
println(sumCombinations(15, List(1, 2, 5, 10)) mkString "\n")
}
Lorsqu'il est exécuté, il affiche:
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2)
List(1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2)
List(1, 1, 1, 1, 1, 2, 2, 2, 2, 2)
List(1, 1, 1, 2, 2, 2, 2, 2, 2)
List(1, 2, 2, 2, 2, 2, 2, 2)
List(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5)
List(1, 1, 1, 1, 1, 1, 1, 1, 2, 5)
List(1, 1, 1, 1, 1, 1, 2, 2, 5)
List(1, 1, 1, 1, 2, 2, 2, 5)
List(1, 1, 2, 2, 2, 2, 5)
List(2, 2, 2, 2, 2, 5)
List(1, 1, 1, 1, 1, 5, 5)
List(1, 1, 1, 2, 5, 5)
List(1, 2, 2, 5, 5)
List(5, 5, 5)
List(1, 1, 1, 1, 1, 10)
List(1, 1, 1, 2, 10)
List(1, 2, 2, 10)
List(5, 10)
La sumCombinations()
fonction peut être utilisée seule et le résultat peut être analysé plus en détail pour afficher la «meilleure» solution (la liste la plus courte) ou le nombre de solutions (le nombre de listes).
Notez que même ainsi, les exigences peuvent ne pas être entièrement satisfaites. Il peut arriver que l'ordre de chaque liste dans la solution soit significatif. Dans un tel cas, chaque liste devrait être dupliquée autant de fois qu'il y a de combinaison de ses éléments. Ou nous pourrions être intéressés uniquement par les combinaisons qui sont différentes.
Par exemple, nous pourrions considérer que cela List(5, 10)
devrait donner deux combinaisons: List(5, 10)
et List(10, 5)
. Car List(5, 5, 5)
il pourrait donner trois combinaisons ou une seule, selon les besoins. Pour les entiers, les trois permutations sont équivalentes, mais si nous avons affaire à des pièces, comme dans le "problème de changement de pièces", elles ne le sont pas.
Il n'est pas non plus indiqué dans les exigences la question de savoir si chaque numéro (ou pièce) ne peut être utilisé qu'une ou plusieurs fois. Nous pourrions (et nous devrions!) Généraliser le problème à une liste de listes d'occurrences de chaque nombre. Cela se traduit dans la vie réelle par "quelles sont les façons possibles de gagner une certaine somme d'argent avec un ensemble de pièces (et non un ensemble de valeurs de pièces)". Le problème d'origine n'est qu'un cas particulier de celui-ci, où nous avons autant d'occurrences de chaque pièce que nécessaire pour faire le montant total avec chaque valeur de pièce unique.