Probleme – Le rendu de monnaie : quand le glouton est-il optimal ?
Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 16 — Algorithmes gloutons
Énoncé
- Écrire le calcul exact du nombre minimal de pièces.
- Le comparer au glouton, et proposer un test décidant si un système donné est canonique — c'est-à-dire si le glouton y est toujours optimal.
- Justifier que ce test peut se limiter à un intervalle borné, et le vérifier.
Corrigé
1. Le calcul exact. On note le nombre minimal de pièces pour rendre .
(* Nombre minimal de pièces pour rendre s, ou None si c'est impossible.
Précondition : pièces > 0, s >= 0. Complexité : Theta(s * |pièces|).
INVARIANT : après le tour k, d.(j) est exact pour tout j <= k. *)
let optimum pieces s =
let d = Array.make (s + 1) max_int in
d.(0) <- 0;
for k = 1 to s do
List.iter (fun c ->
if c <= k && d.(k - c) <> max_int && d.(k - c) + 1 < d.(k)
then d.(k) <- d.(k - c) + 1) pieces
done;
if d.(s) = max_int then None else Some d.(s)
Correction : toute solution optimale pour emploie au moins une pièce , et le reste est rendu de façon optimale — sans quoi on l'améliorerait. D'où , ce que la boucle calcule. C'est la sous-structure optimale du chapitre chap:dynamique.
2. Le test de canonicité. Un système est canonique si le glouton donne l'optimum pour toute somme. Le test consiste donc à comparer les deux fonctions :
(* Nombre de pièces rendues par le glouton, ou None s'il se bloque.
Précondition : pièces > 0, s >= 0. Complexité : Theta(|pièces| log |pièces| + s). *)
let glouton_monnaie pieces s =
let p = Array.of_list (List.sort (fun a b -> compare b a) pieces) in
let reste = ref s and n = ref 0 in
Array.iter (fun c -> while !reste >= c do reste := !reste - c; incr n done) p;
if !reste = 0 then Some !n else None
(* Vrai si le glouton est optimal pour toute somme de 1 à borne. *)
let canonique_jusqua pieces borne =
let ok = ref true in
for s = 1 to borne do
if glouton_monnaie pieces s <> optimum pieces s then ok := false done;
!ok
Mesuré, avec la borne où et sont les deux plus grosses pièces :
| Système | borne | premier échec | échec borne ? |
|---|---|---|---|
| 70 | aucun | --- | |
| 35 | aucun | --- | |
| 7 | 6 | oui | |
| 17 | 14 | oui | |
| 40 | 30 | oui | |
| 41 | 12 | oui |
Aucun système n'a jamais échoué au-delà de sa borne : les recherches ont été poussées jusqu'à .
3. Pourquoi une borne suffit. C'est le théorème de Kozen et Zaks : si un système n'est pas canonique, son plus petit contre-exemple est strictement inférieur à . L'idée en est la suivante — soit le plus petit contre-exemple. Si , alors le glouton et l'optimum emploient tous deux au moins une pièce : on peut la retirer des deux et obtenir un contre-exemple plus petit, contradiction. Le cas est le seul possible.
Ce que ce théorème change. Sans lui, « le glouton est-il optimal sur ce système ? » est une question sur une infinité de sommes, donc indécidable par simple essai. Avec lui, elle se tranche par un calcul fini, en — quelques microsecondes pour un système monétaire réel.
Et c'est la bonne façon de conclure le chapitre. Le cours dit : « un glouton se démontre, ou ne s'emploie pas ». Ce problème montre le troisième terme de l'alternative, souvent le plus utile en pratique : on peut parfois décider mécaniquement si un glouton est correct, sans le démontrer à la main ni se contenter d'un essai. C'est le meilleur des trois mondes, et cela ne s'obtient qu'en démontrant, une fois, un théorème sur le problème lui-même.
Les autres exercices de ce chapitre Le cours du chapitre
Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.