Algorithmes gloutons
Cours complet · informatique (tronc commun des prépas scientifiques), chapitre 7 · prépas scientifiques, tronc commun
Travailler ce chapitre sur Adloun Exercices corrigés de ce chapitre
<i class="fa-solid fa-compass mr-2" style="color:#9A563B"></i>7.1 Introduction et motivation
Le chapitre 6 s'est achevé sur un mur : énumérer toutes les solutions coûte ou , hors de portée dès que dépasse quelques dizaines. Comment choisir, alors, parmi un nombre astronomique de possibilités ? La stratégie la plus simple porte un nom gourmand : l'algorithme glouton (greedy) construit sa solution pas à pas en faisant, à chaque étape, le choix qui paraît localement le meilleur — la plus grosse pièce, l'activité qui finit le plus tôt — sans jamais revenir en arrière.
Cette stratégie a deux visages, et le chapitre les montre tous deux. Sur certains problèmes — la sélection d'activités, l'allocation de salles, le rendu de monnaie en euros — le glouton est non seulement rapide mais exactement optimal, et l'on saura le prouver : c'est l'argument d'échange, le troisième grand schéma de preuve du semestre après l'invariant et la récurrence. Sur d'autres — le rendu de monnaie dans un mauvais système, le sac à dos — le glouton se trompe, et il faut savoir exhiber le contre-exemple. La compétence visée n'est donc pas « appliquer le glouton », mais bien : proposer un critère glouton, et trancher, preuve ou contre-exemple à l'appui, s'il est correct.
7.2 Le principe glouton
Un algorithme glouton construit une solution par une suite de choix tels que :
- chaque choix est fait selon un critère local (le meilleur candidat du moment, pour un certain ordre) ;
- chaque choix est irrévocable : jamais l'algorithme ne revient sur une décision prise.
La structure typique : trier les candidats selon le critère, puis les examiner dans cet ordre en prenant chacun s'il est compatible avec les choix déjà faits.
Le glouton est rapide par construction : un tri (, chapitre 9) suivi d'un parcours (). Toute la question est ailleurs : la suite de choix localement bons est-elle globalement optimale ? En général, non — gravir la pente la plus raide ne mène pas au plus haut sommet. Mais sur des problèmes bien structurés, oui, et c'est démontrable.
7.3 Le rendu de monnaie
7.3.1 L'algorithme
Rendre euros avec le moins de pièces et billets possible : tout le monde fait pareil — un billet de , une pièce de , deux de . C'est le glouton : à chaque étape, la plus grande valeur qui ne dépasse pas le restant. En centimes, avec le système euro (on s'arrête au billet de 5 pour l'exemple) :
def rendu_monnaie(montant: int, systeme: list) -> list:
"""Renvoie la liste des valeurs rendues (avec répétitions).
Préconditions : montant >= 0, systeme trié décroissant et contenant 1."""
rendu = []
for piece in systeme:
# Invariant : montant = montant initial - somme des pièces de rendu,
# et aucune pièce > piece ne peut plus servir
while montant >= piece:
rendu.append(piece)
montant -= piece
return rendu
assert rendu_monnaie(640, [500, 200, 100, 50, 20, 10, 5, 2, 1]) \
== [500, 100, 20, 20]
assert rendu_monnaie(0, [500, 200, 100, 50, 20, 10, 5, 2, 1]) == []
Terminaison : à chaque tour de la boucle interne, montant décroît strictement (variant) ; la précondition « le système contient » garantit qu'on atteint toujours — sans elle, rendu_monnaie(3, [2]) laisserait un reste. Coût : pour valeurs et pièces rendues.
7.3.2 Optimal ici, faux ailleurs
Tout dépend du système de pièces. Avec le système et le montant :
Le choix local « prendre » paraît le meilleur — il laisse le plus petit reste — mais il interdit la décomposition : voilà, sur quatre nombres, toute la faillibilité du glouton. Les systèmes pour lesquels le glouton est optimal pour tout montant sont dits canoniques ; le système de l'euro l'est (admis — la preuve, valeur par valeur, est un exercice), le système ne l'est pas.
Méthode : Que faire face à un glouton douteux ?
Devant un critère glouton proposé, deux issues, et une seule démarche :
- chercher un petit contre-exemple (souvent ou éléments suffisent — qu'on peut traquer par énumération exhaustive du chapitre 6 sur de petites instances : comparer le glouton à la solution optimale énumérée) ;
- si aucun contre-exemple ne vient, tenter la preuve d'échange (section suivante).
Affirmer l'optimalité sans preuve, ou la nier sans contre-exemple, sont deux fautes égales.
7.4 La sélection d'activités
7.4.1 Le problème et le bon critère
On dispose d'une salle et de activités, chacune avec une heure de début et une heure de fin . Deux activités sont compatibles si leurs intervalles ne se chevauchent pas. Objectif : sélectionner un ensemble d'activités deux à deux compatibles, de cardinal maximal.
Trois critères gloutons plausibles :
- la plus courte d'abord ? Contre-exemple : , , — la courte bloque les deux longues : glouton activité, optimal .
- celle qui commence le plus tôt ? Contre-exemple : , , — la lève-tôt occupe tout : glouton , optimal .
- celle qui finit le plus tôt : aucune de ces embûches — et pour cause : c'est le critère optimal, comme on va le prouver.
def selection_activites(activites: list) -> list:
"""activites : liste de couples (debut, fin). Renvoie une sélection
de cardinal maximal d'activités deux à deux compatibles."""
tri = sorted(activites, key=lambda a: a[1]) # par date de FIN croissante
choisies = []
fin_courante = None
for (d, f) in tri:
# Invariant : choisies est compatible, et fin_courante est la
# date de fin de la dernière activité choisie
if fin_courante is None or d >= fin_courante:
choisies.append((d, f))
fin_courante = f
return choisies
a = [(1, 4), (3, 5), (0, 6), (5, 7), (3, 9), (6, 10), (8, 11)]
assert selection_activites(a) == [(1, 4), (5, 7), (8, 11)]
Coût : le tri en , puis un parcours en .
7.4.2 La preuve d'échange
La sélection produite par l'algorithme ci-dessus est de cardinal maximal.
Démonstration
Notons les activités choisies par le glouton, dans l'ordre, et soit une sélection optimale, rangée par dates de fin croissantes. Montrons d'abord, par récurrence sur , que le glouton finit toujours au plus tard en même temps : pour tout .
Base : est, parmi toutes les activités, l'une de celles qui finissent le plus tôt — en particulier . Hérédité : supposons . L'activité commence après : elle était donc compatible avec les choix du glouton au moment où celui-ci a choisi , et disponible. Le glouton ayant pris l'activité compatible qui finit le plus tôt, . ✓
Supposons alors . L'activité commence après : elle est compatible avec toute la sélection gloutonne — mais alors le glouton, qui parcourt toutes les activités, l'aurait acceptée (elle ou une autre) comme -ième choix : contradiction avec le fait qu'il s'est arrêté à . Donc : le glouton est optimal. (Le cœur de l'argument : « le choix glouton ne ferme aucune porte » — toute solution optimale peut être échangée, activité par activité, contre la solution gloutonne sans perdre en cardinal. C'est le schéma de preuve à retenir, et à réutiliser tel quel pour les salles.)
7.5 L'allocation de salles
Mêmes activités, mais cette fois toutes doivent avoir lieu : combien faut-il de salles au minimum, et comment les attribuer ? (C'est le problème de l'emploi du temps — ou des quais de gare, ou des machines.)
On traite les cours par début croissant, en réutilisant une salle libre dès que possible :
def allocation_salles(activites: list) -> list:
"""Renvoie une liste de salles, chacune étant la liste de ses activités.
Le nombre de salles renvoyé est minimal."""
tri = sorted(activites) # par DÉBUT croissant
salles = [] # salles[i] : liste d'activités ; on
fins = [] # mémorise la fin de la dernière de chacune
for (d, f) in tri:
# Invariant : les activités déjà placées sont compatibles dans chaque salle
placee = False
for i in range(len(salles)):
if fins[i] <= d: # la salle i est libre à l'instant d
salles[i].append((d, f))
fins[i] = f
placee = True
break
if not placee: # aucune salle libre : on en ouvre une
salles.append([(d, f)])
fins.append(f)
return salles
Démonstration (Optimalité)
Disons que l'algorithme ouvre salles, et considérons l'instant où la -ième est ouverte : l'activité qui arrive commence en et aucune des salles n'est libre — chacune héberge une activité qui a commencé avant (tri par débuts) et finit après . Il existe donc activités simultanément en cours à l'instant . Or deux activités simultanées ne peuvent partager une salle : toute solution utilise au moins salles. Notre allocation en utilise exactement : elle est minimale. (La preuve exhibe un certificat : activités deux à deux incompatibles. Le nombre minimal de salles est ainsi coincé entre notre solution, qui en donne , et le certificat, qui en exige — encadrement parfait, et l'occasion de noter que la borne inférieure se lit sur le problème, pas sur l'algorithme.)
La recherche d'une salle libre par parcours coûte par activité, d'où au pire — quadratique si presque tout se chevauche. Une structure adaptée (file de priorité sur les dates de fin, second semestre) ramène le tout à . L'idée gloutonne ne change pas, seule l'intendance s'améliore : idée et implémentation sont deux étages distincts de l'analyse.
<i class="fa-solid fa-dumbbell mr-2" style="color:#2E7559"></i>7.6 Exercices résolus
Niveau (Application directe du cours)
Donner le rendu glouton de euros (en centimes : ) dans le système euro complet , vérifier avec la fonction du cours, et compter les pièces. Le glouton peut-il rendre avec moins de pièces ? (On admettra le caractère canonique du système euro.)
Démonstration (Solution)
À la main : — cinq pièces (, , , , ). La machine confirme : rendu_monnaie(263, [200, 100, 50, 20, 10, 5, 2, 1]) renvoie [200, 50, 10, 2, 1]. Le système euro étant canonique (admis), ce rendu de pièces est optimal : aucune décomposition de en valeurs du système n'utilise pièces ou moins. (Petit contrôle de cohérence indépendant : avec pièces au plus et une valeur maximale de , on atteint au mieux — l'argument grossier ne suffit donc pas à conclure, et c'est bien la canonicité qui travaille.)
Dans le système , trouver le plus petit montant pour lequel le glouton n'est pas optimal, en donnant les deux décompositions.
Démonstration (Solution)
Testons les montants croissants. Pour , le glouton n'utilise que et : est clairement optimal (une seule façon raisonnable). Pour : glouton ( pièces) ; or ( pièces) — non optimal, et les montants se vérifient un à un favorables au glouton ( ; ; contre : le glouton gagne ; contre : le glouton gagne). Le plus petit contre-exemple est donc . (La méthode vaut mieux que le résultat : énumérer les petits montants, comparer glouton et optimal — à la main ici, par programme dès que le système grossit ; c'est l'exercice 27 de la banque.)
Sept activités : , , , , , , . Dérouler l'algorithme glouton (tri par fin, parcours) et donner la sélection — puis vérifier qu'aucune sélection de cardinal supérieur n'existe.
Démonstration (Solution)
Tri par date de fin : , , , , , , . Parcours : prise (fin courante ) ; rejetée () ; prise ( — bornes : la fin est exclue, commence quand s'achève ; fin courante ) ; rejetée () ; prise (, fin ) ; rejetée () ; prise (). Sélection : , cardinal .
Optimalité : par le théorème du cours, le glouton est optimal — mais vérifions par certificat direct : à tout choix de activités, le principe des tiroirs appliqué aux quatre créneaux , , , … est ici inutilement subtil ; le plus simple est d'observer que les fins s'étalent de à et que cinq intervalles disjoints exigeraient une durée totale d'au moins dans , ce qui ne conclut pas non plus — la preuve générale du cours est, de fait, le bon argument, et c'est précisément sa valeur : elle dispense de l'examen cas par cas. (Honnêteté de méthode : quand le certificat ad hoc devient laborieux, c'est le théorème général qu'il faut citer.)
Niveau (Application avec raisonnement intermédiaire)
Avec les sept activités de l'exercice 3, dérouler l'allocation de salles, donner le nombre de salles obtenu, et exhiber le certificat d'optimalité (l'instant critique et ses activités simultanées).
Démonstration (Solution)
Tri par début : , , , , , , — le tri lexicographique de sorted départage les débuts égaux par la fin : passe avant , avant . Parcours : salle 1 (fin ) ; : salle 1 occupée () salle 2 (fin ) ; : salle 1 libre () salle 1 (fin ) ; : salle 1 () non, salle 2 () non salle 3 (fin ) ; : salle 1 libre () salle 1 (fin ) ; : salle 1 () non, salle 2 () oui salle 2 (fin ) ; : salle 1 () salle 1. Trois salles.
Certificat : à l'instant par exemple, , et sont toutes trois en cours — trois activités deux à deux incompatibles : toute solution exige au moins salles. Le glouton en utilise : optimal. (Le déroulé montre l'instant exact où la troisième salle s'ouvre — l'arrivée de — et c'est bien là que vit le certificat, comme dans la preuve générale.)
Un randonneur dispose d'un sac de capacité kg et de denrées divisibles : kg de valeur , kg de valeur , kg de valeur . Quel est le critère glouton correct, et quelle valeur maximale emporte-t-il ? Montrer que le critère « plus grande valeur d'abord » est, lui, sous-optimal.
Démonstration (Solution)
Quand on peut fractionner, le bon critère est la valeur au kilo : , , . Tri décroissant : la denrée à /kg ( kg), puis celle à /kg ( kg), puis celle à /kg. Le sac prend kg (valeur ), puis kg (valeur ) — il est plein : valeur totale .
Critère « plus grande valeur d'abord » : on prend les kg de valeur , puis kg sur les kg de valeur (fraction , valeur ) : total — sous-optimal.
L'optimalité de la valeur au kilo se voit par échange : si une solution emporte du poids d'une denrée moins dense alors qu'il reste de la plus dense, remplacer un gramme de l'une par un gramme de l'autre augmente la valeur — toute solution optimale remplit donc le sac par densités décroissantes, ce que fait le glouton. (Retenir le distinguo, qui prépare l'exercice 8 : fractionnable le glouton par densité est optimal ; indivisible il ne l'est plus.)
Au guichet, clients ont des durées de service connues. L'ordre de passage change la somme des temps d'attente (chacun attend la fin de tous ses prédécesseurs). Quel ordre la minimise ? Le prouver par échange.
Démonstration (Solution)
Critère : servir par durées croissantes (le plus court d'abord). Intuition : la durée du premier client est subie par les suivants, celle du deuxième par , etc. — la somme des attentes vaut : il faut affecter les grands coefficients aux petites durées.
Preuve d'échange : soit un ordre optimal où deux clients consécutifs vérifient ( passe juste avant ). Échangeons-les : seules leurs attentes mutuelles changent — avant l'échange, attend de plus ; après, attend de plus ; la somme varie de : elle diminue strictement, contredisant l'optimalité. Donc dans tout ordre optimal, les durées consécutives sont croissantes — l'ordre croissant est optimal. (L'argument « si deux voisins violent le critère, les échanger améliore » est la forme la plus pure de la preuve d'échange ; on remarquera son parfum de tri à bulles — corriger les inversions du critère — ce qui n'est pas un hasard : trier selon le bon critère est l'algorithme.)
Une voiture parcourt un circuit de stations-service ; elle peut parcourir kilomètres par plein, et les stations sont aux positions croissantes (l'arrivée est ). Donner le glouton qui minimise le nombre d'arrêts, le prouver, et préciser la condition de faisabilité.
Démonstration (Solution)
Faisabilité : il faut pour tout — sinon un tronçon est infranchissable, quel que soit l'algorithme.
Glouton : partir le plein fait, et à chaque arrêt, aller le plus loin possible — s'arrêter à la dernière station atteignable.
def arrets(p: list, K: int) -> list:
"""p : positions croissantes, p[0] = 0 = départ, p[-1] = arrivée.
Renvoie les positions des arrêts (hors départ/arrivée)."""
stops, position = [], 0
i = 0
while p[i] != p[-1]:
# aller à la dernière station accessible depuis 'position'
while i + 1 < len(p) and p[i + 1] - position <= K:
i += 1
stops.append(p[i])
position = p[i]
return stops[:-1] if stops and stops[-1] == p[-1] else stops
Preuve (échange, version « le glouton domine ») : notons les positions des arrêts gloutons et ceux d'une solution optimale. Par récurrence, pour tout : au premier arrêt, le glouton va par définition aussi loin que possible, donc ; et si , le glouton repart d'au moins aussi loin et choisit de nouveau le point accessible le plus lointain, donc . Le glouton, toujours en avance, atteint l'arrivée avec au plus autant d'arrêts. (Variante du schéma d'échange dite « le glouton reste devant » — la même qui prouvait pour les activités : repérer cette structure de preuve dans les deux cas est tout l'enjeu du chapitre.)
Niveau (Raisonnement subtil ou plusieurs étapes)
Sac de capacité kg, objets indivisibles : , , — les mêmes qu'à l'exercice 5. Montrer que les trois critères gloutons naturels (valeur, densité, poids croissant) sont tous sous-optimaux ici, et trouver l'optimum par énumération des sous-ensembles (chapitre 6).
Démonstration (Solution)
Les sous-ensembles tenant dans kg : ; ; ; kg, valeur ; kg, valeur ; kg : trop lourd ; : trop lourd. Optimum : avec .
Les gloutons : par valeur — prend , puis ne tient pas, puis tient : , valeur … optimal ici ! Construisons alors mieux : remplaçons l'objet 2 par . Énumération : ; ; … optimum toujours . Par valeur : prend puis ne tient pas puis : — encore optimal. Le contre-exemple demande un peu plus de soin : capacité , objets , , . Par valeur et par densité ( ; ; ) : prennent , plus rien ne tient — valeur ; par poids croissant : … qui est l'optimum (l'énumération le confirme : , , sont les seules valeurs atteignables). Donc valeur et densité échouent (). Pour faire chuter aussi le poids croissant : capacité , objets , , — poids croissant prend puis : ; l'optimum est . Aucun des trois critères n'est correct en général. (Le sac à dos indivisible est un problème difficile au sens fort — comme la somme de sous-ensemble du chapitre 6, dont il est cousin ; le glouton y sert de solution approchée, jamais garantie. La frontière exacte avec l'exercice 5 tient en un mot : la divisibilité — qui autorise l'argument d'échange « gramme contre gramme », impossible sur des objets entiers.)
élèves ont des tailles ; on doit les ranger sur une ligne de emplacements de hauteurs (un élève par emplacement), en minimisant le plus grand écart . Montrer que l'appariement glouton « trier les deux listes et apparier par rang » est optimal.
Démonstration (Solution)
Supposons les deux listes triées : et ; le glouton apparie avec . Soit un appariement optimal quelconque : s'il contient un croisement — deux indices avec appariés à — décroisons-les (apparier et ). Vérifions que le maximum des deux écarts ne croît pas : en notant les tailles et les hauteurs, il s'agit de voir
Or les quatre points et sur la droite réelle vérifient : (si , alors ; sinon ) et de même pour . ✓ Chaque décroisement supprime au moins une inversion entre les deux listes sans augmenter le critère : en itérant (le nombre d'inversions est un variant !), on atteint l'appariement croissant du glouton, de critère au plus égal — il est optimal. (Trois chapitres se rejoignent : la preuve d'échange du jour, le variant du chapitre 1, et les inversions du chapitre 3. L'inégalité centrale — « apparier dans l'ordre n'aggrave jamais le pire écart » — resservira sous d'autres habits, des files d'attente aux statistiques.)
Écrire un banc d'essai qui compare selection_activites à l'optimum calculé par énumération exhaustive (chapitre 6) sur des milliers de petites instances aléatoires — puis l'appliquer au critère faux « la plus courte d'abord » pour mesurer sa fréquence d'échec et son écart moyen à l'optimum.
Démonstration (Solution)
import random
def compatibles(sel: list) -> bool:
s = sorted(sel)
return all(s[i][1] <= s[i + 1][0] for i in range(len(s) - 1))
def optimum_brut(activites: list) -> int:
meilleur = 0
for sous in sous_listes(activites): # chapitre 6 : 2**n candidats
if compatibles(sous):
meilleur = max(meilleur, len(sous))
return meilleur
def plus_courte_d_abord(activites: list) -> list:
tri = sorted(activites, key=lambda a: a[1] - a[0])
choisies = []
for (d, f) in tri:
if all(f <= d2 or f2 <= d for (d2, f2) in choisies):
choisies.append((d, f))
return choisies
random.seed(7)
echecs, ecart_total, essais = 0, 0, 2000
for _ in range(essais):
acts = []
for _ in range(random.randint(1, 8)): # petites instances : 2**8 max
d = random.randint(0, 20)
acts.append((d, d + random.randint(1, 6)))
opt = optimum_brut(acts)
assert len(selection_activites(acts)) == opt # JAMAIS d'écart
courte = len(plus_courte_d_abord(acts))
if courte < opt:
echecs += 1
ecart_total += opt - courte
print(echecs / essais, ecart_total / max(echecs, 1))
# 2 % d'échecs (39 sur 2000 avec cette graine), écart moyen 1 quand il y a échec
Le banc confirme expérimentalement le théorème — aucun écart pour le critère par date de fin sur instances — et chiffre la faillite du critère naïf : il échoue sur une petite fraction des instances — environ une sur cinquante ici —, généralement d'une activité ; rare ne veut pas dire correct : un seul échec suffit à réfuter. (Trois usages de ce banc : conjecturer (un glouton qui survit à instances aléatoires mérite qu'on tente la preuve), réfuter (le premier échec est un contre-exemple, que le banc peut afficher), et mesurer (un glouton faux peut rester une bonne heuristique — décision d'ingénieur, à prendre chiffres en main). La force brute exponentielle, inutilisable en production, trouve ici son vrai métier : juge de paix sur petites instances.)
- Glouton : trier selon un critère local, choisir irrévocablement chaque candidat compatible ; coût typique — la rapidité est garantie, l'optimalité jamais a priori.
- La démarche : critère proposé chercher un petit contre-exemple (à la main ou par banc force-brute sur petites instances) ; s'il résiste preuve d'échange.
- Preuve d'échange, trois variantes : « le glouton reste devant » (activités : ; essence : ) ; « échanger deux voisins qui violent le critère améliore » (guichet, photographe — avec le nombre d'inversions comme variant) ; « certificat » (salles : activités simultanées au moins salles — l'optimum est coincé).
- Rendu de monnaie : glouton optimal sur les systèmes canoniques (euro : admis), faux ailleurs — : contre ; : premier échec à .
- Sélection d'activités : critère correct date de fin croissante (plus courte d'abord et début au plus tôt : contre-exemples) ; salles : tri par débuts, réutiliser une salle libre, optimal par certificat.
- Sac à dos : fractionnable densité (valeur/poids) optimale par échange gramme à gramme ; indivisible tous les critères naïfs ont des contre-exemples — problème difficile, glouton heuristique.
- Le banc force-brute (énumérations du chapitre 6 sur ) : conjecturer, réfuter (premier échec contre-exemple), mesurer la qualité d'une heuristique.
7.7 Exercices d'entraînement
Cette banque d'exercices, classée par thème, couvre l'intégralité du chapitre. La numérotation prolonge celle des dix exercices résolus. Légende : application directe, raisonnement intermédiaire, approfondissement ; le symbole signale un classique incontournable.
A. Rendu de monnaie
- () Donner les rendus gloutons de , et centimes dans le système euro, et compter les pièces.
- () Dans le système (à l'américaine, sans le nickel), montrer que est un contre-exemple ; est-ce le plus petit ?
- ( ) Adapter
rendu_monnaiepour renvoyer le dictionnaire valeur nombre de pièces, et n'utiliser que des divisions entières (montant // piece) au lieu de la bouclewhile— comparer les coûts. - () Le système des timbres : trouver par programme tous les montants où le glouton échoue, et la pire perte (écart maximal au nombre optimal de timbres, calculé par force brute).
- () Montrer que tout système de la forme (puissances d'une base ) est canonique — la preuve passe par l'écriture en base et l'unicité du développement avec chiffres .
B. Activités et planification
- () Huit films au festival, horaires donnés ; appliquer le glouton par date de fin et donner le programme du cinéphile.
- () Construire une instance où la sélection optimale n'est pas unique, et vérifier que le glouton en trouve une.
- ( ) Adapter la sélection d'activités au cas où l'on dispose de deux salles (sélectionner un cardinal maximal d'activités plaçables sur deux lignes) : le glouton « date de fin, salle la plus chargée possible » est-il optimal ? Expérimenter contre la force brute avant de conclure.
- () Des conférences avec priorités : maximiser non plus le nombre mais la somme des durées des activités retenues. Montrer par contre-exemple que le glouton par date de fin n'est plus optimal.
- () tâches d'une heure, chacune avec une échéance et une pénalité si elle est rendue après son échéance. Glouton : traiter par pénalités décroissantes en plaçant chaque tâche au créneau libre le plus tardif avant son échéance. L'implémenter et le confronter à la force brute sur petites instances.
C. Preuves d'échange
- ( ) Reprendre la preuve « le glouton reste devant » de la sélection d'activités en rédigeant soigneusement la récurrence — c'est la démonstration à savoir refaire.
- () Au guichet de l'exercice 6, deux serveurs au lieu d'un : proposer le glouton (durées croissantes, serveur le moins chargé) et tester contre la force brute ; que conjecture-t-on ?
- () Couper une planche de longueur en morceaux donnés, chaque coupe coûtant la longueur de la planche coupée : montrer par contre-exemple que couper « le plus grand morceau d'abord » n'est pas toujours optimal (problème dont la solution exacte attendra les arbres, au second semestre).
- ( ) couples (skieur, paire de skis) : tailles et longueurs , minimiser la somme des . Adapter la preuve de décroisement de l'exercice 9 (l'inégalité change : la somme remplace le max) et conclure que l'appariement trié reste optimal.
D. Quand le glouton échoue — et que faire
- () Sur le sac à dos indivisible de capacité avec objets , , : calculer les trois gloutons et l'optimum.
- () Le voyageur pressé : visiter villes en partant de la plus proche à chaque étape (glouton du « plus proche voisin »). Construire une configuration de points où ce glouton ne donne pas le plus court circuit — quatre points suffisent.
- ( ) Écrire le banc générique
teste_glouton(glouton, optimum, generateur, essais)(exercice résolu 10 factorisé) et l'appliquer à trois problèmes du chapitre ; faire afficher le premier contre-exemple rencontré. - () Pour le rendu de monnaie général, écrire
rendu_optimal(montant, systeme)par énumération récursive avec l'élagage suivant : abandonner toute branche utilisant déjà autant de pièces que la meilleure solution connue. Mesurer jusqu'à quel montant l'exact reste praticable, et l'écart du glouton sur . - ( ) Étude de synthèse : pour le problème des salles, rédiger le rapport complet — algorithme, coût, preuve d'optimalité par certificat, banc de validation contre la force brute, et limites (que devient le problème si chaque activité exige une salle d'une capacité donnée ?) — au format des six compétences du programme (analyser, concevoir, spécifier, mettre en œuvre, justifier, communiquer).