====== 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.