CHAPITRE 3 : QUAND LE GLOUTON SE TROMPE

Tonton Émile fait la ligne Yaoundé–Douala. Dans la soute de son car, il lui reste 15 kilos à vendre pour le compte de commerçants. Plusieurs marchandises lui sont proposées. Il doit choisir, et il va se tromper.

Ce qu'on lui propose

MarchandisePoidsValeur Valeur au kilo
Poivre de Penja9 kg100 000 FCFA 11 111 FCFA/kg
Cacao12 kg70 000 FCFA5 833 FCFA/kg
Safou2 kg10 000 FCFA5 000 FCFA/kg
Ndolé séché7 kg30 000 FCFA4 286 FCFA/kg
Miel d'Oku5 kg20 000 FCFA4 000 FCFA/kg

Les sacs ne se coupent pas : on prend la marchandise entière, ou on la laisse. C'est ce qu'on appelle le sac à dos 0-1 : zéro ou un exemplaire, jamais une moitié.

Le raisonnement de Tonton Émile

Il est transporteur depuis vingt ans, et sa règle est simple : je charge d'abord ce qui rapporte le plus au kilo. C'est un critère glouton, et il est tout à fait raisonnable.

  1. Le poivre de Penja rapporte 11 111 FCFA/kg. Il le prend. 9 kg chargés, 6 restants.
  2. Le cacao vient ensuite, mais il pèse 12 kg. Impossible.
  3. Le safou ? 2 kg, ça rentre. Il le prend. 11 kg chargés, 4 restants.
  4. Le ndolé pèse 7 kg, le miel 5 kg. Ni l'un ni l'autre ne rentre dans les 4 kg qui restent.

Chargement final : 11 kg pour 110 000 FCFA

Ce qu'il aurait fallu faire

Comparaison de deux chargements de 15 kg : le glouton prend le poivre et le safou pour 110 000 FCFA en laissant 4 kg vides, l'optimum prend le poivre et le miel pour 120 000 FCFA.

En testant les 32 combinaisons possibles, on trouve mieux :

Poivre (9 kg) + Miel d'Oku (5 kg) = 14 kg pour 120 000 FCFA

Tonton Émile a perdu 10 000 FCFA, soit 8,3 % de ce qu'il pouvait gagner. Sur une ligne qu'il fait deux fois par semaine, cela fait plus d'un million de francs sur l'année.

Où est l'erreur ?

Elle n'est pas dans le critère. Le safou rapporte bien plus au kilo que le miel : 5 000 contre 4 000. Le glouton a correctement appliqué sa règle.

L'erreur est ailleurs : en prenant le safou, qui ne pèse que 2 kg, Tonton Émile s'est retrouvé avec 4 kg inutilisables. Trop peu pour le miel, trop peu pour le ndolé. Ces 4 kg sont partis à vide.

Le miel rapporte moins au kilo, mais il remplit mieux le car. Le glouton ne sait pas voir cela : il regarde les marchandises une par une, pas la place qu'elles laissent derrière elles.

C'est le défaut structurel du glouton. Il évalue chaque candidat isolément. Il lui faudrait anticiper : se demander « si je prends celui-ci, qu'est-ce que je pourrai encore prendre après ? », et c'est précisément ce qu'il ne fait jamais.

Anticiper, c'est le travail de la programmation dynamique, plus lente mais exacte.

Le code, quand même

Même imparfait, l'algorithme reste utile. Le voici :

def charger(marchandises, capacite):
    # marchandises : liste de (nom, poids, valeur). Renvoie (valeur, chargement)
    # on trie du plus rentable au kilo au moins rentable
    par_densite = sorted(marchandises,
                         key=lambda m: m[2] / m[1],
                         reverse=True)

    poids, valeur, pris = 0, 0, []

    for nom, p, v in par_densite:
        if poids + p <= capacite:        # ca rentre encore
            pris.append(nom)
            poids += p
            valeur += v

    return valeur, pris, poids
>>> charger(MARCHANDISES, 15)
(110000, ['Poivre de Penja', 'Safou'], 11)

Et la force brute ?

from itertools import combinations


def charger_exact(marchandises, capacite):
    # Teste toutes les combinaisons. Exact, mais exponentiel
    meilleur = (0, ())

    for taille in range(len(marchandises) + 1):
        for essai in combinations(marchandises, taille):
            poids = sum(m[1] for m in essai)
            if poids <= capacite:
                valeur = sum(m[2] for m in essai)
                if valeur > meilleur[0]:
                    meilleur = (valeur, essai)

    return meilleur

Sur cinq marchandises, c'est instantané : 32 combinaisons. Sur cinquante, c'est un million de milliards : inenvisageable.

Alors, faut-il jeter le glouton ?

Non. Il faut savoir ce qu'on achète.

GloutonForce brute
Résultat110 000 FCFA120 000 FCFA
Écart8,3 %
Temps sur 5 objetsimmédiatimmédiat
Temps sur 50 objetsimmédiatdes siècles

Perdre 8 % sur un calcul instantané est souvent un bon marché. Et on peut démontrer que ce glouton-là ne descend jamais en dessous de la moitié de l'optimum : il est mauvais, mais pas catastrophique.

Au chapitre suivant, nous changerons une seule règle du problème, et le même glouton deviendra parfaitement optimal.

À retenir

  • Sac à dos 0-1 : on prend l'objet entier ou pas du tout.
  • Le critère « le plus rentable au kilo » est raisonnable mais pas optimal.
  • Le glouton échoue parce qu'il ignore la place qu'un choix laisse derrière lui.
  • Ici : 110 000 contre 120 000 FCFA, soit 8,3 % perdus.

Exercices d'application

Exercice 1
Vérifiez par vous-même qu'aucune autre combinaison ne dépasse 120 000 FCFA. Combien y a-t-il de chargements réalisables ?
Voir le corrigeMasquer le corrige

Il y a 2⁵ = 32 combinaisons en tout, dont certaines dépassent les 15 kg. Listons celles qui tiennent et rapportent le plus (P = poivre 9 kg, C = cacao 12 kg, S = safou 2 kg, N = ndolé 7 kg, M = miel 5 kg) :

ChargementPoidsValeur
P + M14 kg120 000
P + S11 kg110 000
P + N16 kgdépasse
C + S14 kg80 000
C12 kg70 000
N + M + S14 kg60 000

Le poivre seul vaut déjà 100 000 : toute bonne solution le contient. Avec 6 kg restants, le choix se réduit au safou (2 kg, 10 000) ou au miel (5 kg, 20 000). Le miel gagne.

P + M = 120 000 FCFA est bien l'optimum.

Exercice 2
On ajoute une marchandise : 1 kg de vanille valant 15 000 FCFA. Que fait le glouton, et quel est le nouvel optimum ?
Voir le corrigeMasquer le corrige

La vanille vaut 15 000 FCFA/kg : elle devient la plus rentable, devant le poivre (11 111).

Glouton :

vanille 1 kg   -> 1 kg,  15 000    reste 14 kg
poivre  9 kg   -> 10 kg, 115 000    reste  5 kg
cacao  12 kg   -> ne rentre pas
safou   2 kg   -> 12 kg, 125 000    reste  3 kg
ndole   7 kg   -> ne rentre pas
miel    5 kg   -> ne rentre pas

total : 12 kg, 125 000 FCFA

Optimum : vanille + poivre + miel = 1 + 9 + 5 = 15 kg pour 15 000 + 100 000 + 20 000 = 135 000 FCFA.

Le glouton perd encore 10 000 FCFA, et pour la même raison : le safou lui a mangé 2 kg qui manquaient au miel. Ajouter un objet n'a rien corrigé : le défaut est dans la méthode, pas dans les données.

Exercice 3
Proposez un critère glouton différent et dites s'il ferait mieux ici.
Voir le corrigeMasquer le corrige

Trois critères sont couramment tentés :

CritèreChargementValeur
Valeur au kilo décroissantePoivre + Safou110 000
Valeur absolue décroissantePoivre + Safou110 000
Poids croissantSafou + Miel + Ndolé60 000

La valeur absolue prend d'abord le poivre (100 000), puis le cacao ne rentre pas, puis le ndolé (30 000) ne rentre pas dans 6 kg, puis le miel (20 000) ne rentre pas non plus… puis le safou. Même résultat.

Le poids croissant est franchement mauvais : il remplit le car de petites marchandises sans valeur.

Aucun critère glouton ne trouve 120 000 ici, et ce n'est pas un hasard : on a démontré qu'aucun algorithme glouton ne résout le sac à dos 0-1 de façon optimale dans tous les cas. Changer de critère déplace l'erreur, il ne la supprime pas.

Cherchez avant d'ouvrir le corrige : c'est en butant sur les difficultes que l'on progresse.

Questions / Réponses

Aucune question. Soyez le premier à poser une question.
★ ★ ★ ★ ★
2 votes. Moyenne 5 sur 5.

Ajouter un commentaire

Anti-spam