Adloun

Un glouton prouvé optimal existe

Exercice supplémentaire · niveau 3 (difficile) · NSI (première), chapitre 8 — Dichotomie, voisins et gloutons · Aux frontières

Énoncé

Un glouton prouvé optimal existe : l'ordonnancement d'activités. Étant donné des créneaux , en retenir le plus possible sans chevauchement, en choisissant à chaque étape celui qui finit le plus tôt. Le vérifier contre une résolution exhaustive, puis montrer que trier par durée croissante échoue.

Corrigé


def activites(intervalles):
    """Nombre maximal d'activites compatibles : glouton par fin CROISSANTE.

    Ce glouton-la est PROUVE optimal.
    """
    tries = sorted(intervalles, key=lambda x: x[1])
    fin, choisies = float("-inf"), []
    for debut, f in tries:
        if debut >= fin:
            choisies.append((debut, f))
            fin = f
    return choisies

def activites_exhaustif(intervalles):
    """Oracle : toutes les parties, pour de petites instances."""
    meilleur = 0
    for r in range(len(intervalles) + 1):
        for combi in itertools.combinations(sorted(intervalles), r):
            if all(combi[i][1] <= combi[i + 1][0] for i in range(len(combi) - 1)):
                meilleur = max(meilleur, r)
    return meilleur


I = [(1, 4), (3, 5), (0, 6), (5, 7), (3, 9), (5, 9), (6, 10), (8, 11)]
assert len(activites(I)) == 3
assert activites_exhaustif(I) == 3

for _ in range(300):                    # 300 instances aleatoires
    inter = []
    for _ in range(random.randint(1, 7)):
        a = random.randint(0, 10)
        inter.append((a, random.randint(a + 1, a + 6)))
    assert len(activites(inter)) == activites_exhaustif(inter)

L'idée de la preuve, en deux phrases. Choisir l'activité qui finit le plus tôt laisse le plus de temps possible pour toutes les suivantes ; on montre alors que toute solution optimale peut être transformée, sans perdre d'activité, en une solution qui commence par ce choix. Un tel argument d'« échange » est la façon standard de prouver qu'un glouton est optimal — et c'est justement ce qu'on ne peut pas faire pour le rendu de monnaie avec .

Le même glouton, avec un autre critère, échoue.


def activites_duree(intervalles):
    """Variante : la plus COURTE d'abord."""
    tries = sorted(intervalles, key=lambda x: x[1] - x[0])
    pris = []
    for d, f in tries:
        if all(f <= a or d >= b for a, b in pris):
            pris.append((d, f))
    return pris

piege = [(0, 5), (4, 6), (5, 10)]
assert len(activites_duree(piege)) == 1     # elle prend (4,6), qui bloque les deux autres
assert len(activites(piege)) == 2           # (0,5) puis (5,10)

La plus courte activité, , chevauche les deux autres et les élimine à elle seule. **Ce n'est pas « le glouton » qui est optimal ou non : c'est le critère.** Deux stratégies gloutonnes sur le même problème, l'une prouvée optimale, l'autre fausse sur trois intervalles.

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.