====== Sac à dos ======
===== Présentation =====
Il s'agit d'un problème classique permettant pour lequel une recherche systématique mal construite risquerait de demander trop de temps. Pour ce problème, l'**algorithme glouton** donne de bons résultats.
C'est le problème du **cambrioleur**. Son sac est de taille limitée et il cherche à emporter le plus de valeurs possibles.
On dispose de $n$ objets qui ont chacun un poids $p_i$ et une valeur $v_i$ pour $i$ dans $[[0, n-1]]$ et d'un sac qui peut supporter un poids maximal $P$ . Quels objets faut-il prendre pour **optimiser** le remplissage du sac à dos du point de vue de la valeur transportée ?
Un problème d'optimisation est un problème dans lequel on cherche à maximiser un gain -- ou minimiser une dépense -- tout en respectant une contrainte. Dans le problème du sac à dos, s'il n'y avait pas la contrainte de la capacité maximale du sac, il suffirait de prendre tout ce qu'il y a à prendre. C'est bien parce qu'il y a la contrainte que l'on doit choisir, et pour choisir il nous faut un critère de choix. Notre critère de choix est de rechercher la valeur maximale.
Pour un $n$ petit, la force brute donne un résultat rapidement : pour $n$ objets, il y a $2^n$ choix de sacs possibles. Par exemple, si $n = 10$, on a $2^n = 1024$, on peut envisager de les essayer tous. Mais si $n = 100$, $2^n \simeq 1E30$, on ne pourra les essayer tous !
===== Stratégie gloutonne =====
Le principe d'une stratégie par algorithme glouton est de trier les items dans un certain ordre et de les faire entrer dans le sac dans cet ordre.
Mais quel ordre choisir ?
* Les plus légers en premiers ?
* Les plus hautes valeurs en premiers ?
* Ceux qui ont le meilleur rapport valeur/poids en premier ?
Ces trois choix sont valables. On n'a aucune garantie de trouver la meilleure solution quelque soit l'ordre choisi. On trouvera seulement une bonne solution.
===== La liste d'objets =====
À titre d'exemple, supposons qu'on ait la liste d'objet
^ indice ^ nom ^ poids ^ valeur ^
| 0 | collier | 1 | 600 |
| 1 | écran | 10 | 200 |
| 2 | globe | 7 | 120 |
| 3 | lampe | 5 | 40 |
| 4 | fleur | 4 | 10 |
| 5 | écrin | 2 | 300 |
| 6 | coffre | 25 | 1500 |
| 7 | livre | 5 | 30 |
| 8 | caisse | 12 | 100 |
| 9 | enclume | 20 | 20 |
| 10 | statuette | 6 | 250 |
| 11 | livre rare | 5 | 220 |
Dans le programme on disposera d'une liste ayant cette forme :
liste = [
{"nom":"collier", "poids":1, "valeur":600},
{"nom":"écran", "poids":10, "valeur":200},
{"nom":"globe", "poids":7, "valeur":120},
{"nom":"lampe", "poids":5, "valeur":40},
{"nom":"fleur", "poids":4, "valeur":10},
{"nom":"écrin", "poids":3, "valeur":300},
{"nom":"coffre", "poids":25, "valeur":1500},
{"nom":"livre", "poids":5, "valeur":30},
{"nom":"caisse", "poids":12, "valeur":100},
{"nom":"enclume", "poids":20, "valeur":20},
{"nom":"statuette", "poids":6, "valeur":250},
{"nom":"livre rare", "poids":5, "valeur":220}
]
===== Rappel sur le tri =====
Les items du tableau, il faut préciser par rapport à quelle mesure on doit les ordonner. On doit donc indiquer au tri une fonction $item \mapsto evaluation$.
Par exemple si on veut trier par valeur croissante, il nous faut : $item \mapsto valeur(item)$. On peut définir cette fonction de façon classique :
def critere_valeur(item):
return item["valeur"]
Puis le tri sera :
liste.sort(key = critere_tri)
et si on veut un ordre décroissant, il suffit de le préciser :
liste.sort(key = critere_tri, reverse = True)
On peut aussi (ce sera mieux ici) modifier le critère : si on veut trier par valeur décroissante, il suffit de choisir :
def critere_valeur(item):
return -item["valeur"]
Le ''-'' change naturellement l'ordre de sorte que ''liste.sort(key = critere_tri)'' triera par valeur décroissante.
===== Implémentation =====
- On a besoin de trier le tableau suivant un certain critère. Définissez une fonction critère pour les 3 cas :
* par valeur décroissante,
* par poids croissant,
* par rapport valeur/poids décroissante.
- Voici l'algorithme glouton pour le sac à dos :
FONCTION sac_a_dos
ENTRÉES
liste: tableau contant la liste des objets avec leur nom, poids et valeur
P: poids maximum que peut emporter le sac
critere: la fonction définissant le critère de tri
SORTIE
un tuple contenant :
la liste des noms,
le poids du sac,
la valeur du sac
DÉBUT
initialiser contenu à vide, poids et valeur à 0
trier la liste suivant le critère retenu
POUR CHAQUE item DE liste FAIRE
SI le sac a assez de place pour cet item ALORS
ajouter le nom de cet item au contenu
ajouter le poids et la valeur de cet item à poids et valeur
FIN
FIN
RENVOYER contenu, poids, valeur
- Testez la fonction avec les 3 critères en prenant ''P = 20''.
- Comme dans ce cas le tableau est de petite taille, cherchez le meilleur sac en force brute (c'est à dire en essayant tous les cas) et comparez avec la réponse obtenue avec l'algorithme glouton.
- comparez la complexité de la recherche brute avec la complexité de l'algorithme glouton.