Le problème
On dispose de pièces (en quantités non limitées) de valeurs faciales entières \( v_0 > v_1 > ... > v_n \). On cherche à payer une somme S (entière) avec le minimum de pièces possibles.
Exemple :
on veut payer S = 32 € en disposant de pièces de valeurs faciales v0 = 10 €, v1 = 5 €, v2 = 2 € et v3 = 1 € (on dispose de quantités non limitées de pièces) : on utilisera le minimum de pièces possibles en utilisant trois pièces de 10 et une pièce de 2.
Un algorithme glouton
Dans un premier temps, on met en place un algorithme glouton :
- on donne une pièce de plus grande valeur faciale V possible sans dépasser la somme S.
- S est mise à jour (S reçoit S-V).
- on reprend au point 1 tant qu'on peut.
On supposera que l'on dispose toujours de pièces de valeur faciale 1 (ce qui garantit que toute somme entière est réalisable).
Donner une version récursive de cette fonction gloutonne.
Entrée | la somme à atteindre (entier naturel), une liste des valeurs faciales disponibles (liste d'entiers naturels). |
---|---|
Sortie | Une liste donnant le nombre de pièces à utiliser pour chaque valeur faciale. |
- un code
- version itérative
def monnaie(somme_a_payer, liste_faces_dispo) :
"""
somme_a_payer :
de type entier, c'est la somme à payer.
liste_faces_dispo :
liste des valeurs faciales des pièces disponibles en ordre décroissant,
Le dernier élément de liste_faces_dispo vaut 1,
ceci garantit que le cas de base "somme == 0"
sera toujours atteint.
liste_solution :
liste des nombres de pièces utilisées pour chacune des valeurs faciales
pour payer la somme désirée.
j :
indice permettant de parcourir la liste liste_faces_dispo.
Exemple :
Pour payer somme = 14 en disposant des valeurs faciales liste_faces_dispo = [10,5,2,1],
on utilisera liste_solution = [1,0,2,0] (une pièce de 10 et deux pièces de 2).
"""
liste_solution = [0 for x in liste_faces_dispo]
def money(somme, j) :
if somme == 0 : return liste_solution
elif liste_faces_dispo[j] > somme : return money(somme, j+1)
else :
liste_solution[j] += 1
return money(somme - liste_faces_dispo[j], j)
return money(somme_a_payer, 0)
def affiche_solution(somme_a_payer, liste_faces_dispo) :
liste_solution = monnaie(somme_a_payer, liste_faces_dispo)
print( "Pour payer la somme de {} \u20AC, on utilisera : ".format(somme_a_payer) )
for i, s in enumerate(liste_solution) :
print( "{} pièces de {} \u20AC.".format(s, liste_faces_dispo[i]) )
affiche_solution(32, [10,5,2,1])
Le principe précédent est un simple principe de division euclidienne, d'où la version itérative suivante :
def monnaie(somme_a_payer, liste_faces_dispo):
liste_solution = []
for m in liste_faces_dispo :
liste_solution.append(somme_a_payer//m)
somme_a_payer %= m
return liste_solution
def affiche_solution(somme_a_payer, liste_faces_dispo) :
liste_solution = monnaie(somme_a_payer, liste_faces_dispo)
print( "Pour payer la somme de {} \u20AC, on utilisera : ".format(somme_a_payer) )
for i, s in enumerate(liste_solution) :
print( "{} pièces de {} \u20AC.".format(s, liste_faces_dispo[i]) )
affiche_solution(32, [10,5,2,1])