1NSI : TD Problème du Sac à Dos
& Algorithmes Gloutons⚓︎
Introduction⚓︎
- Le but de ce TD est de présenter un problème classique, le Problème du Sac à Dos
ou Knapsack Problem (KP)
,
- et de le résoudre grâce à la méthode de programmation appelée Heuristique Gloutonne, c'est-à-dire que nous utiliserons des algorithmes gloutons.
Col
On dispose de plusieurs objets, ayant chacun:
- un poids \(p_i\)
- et une valeur \(v_i\) (par exemple en €)
On dispose d'un sac à dos qui supporte un poids maximal à ne pas dépasser \(P_{max}\).
Le problème du sac à dos consiste à remplir le sac à dos avec ces objets, de sorte que:
- le poids final du sac à dos ainsi rempli, ne dépasse pas le poids maximal \(P_{max}\) supporté par le sac à dos
- la somme totale de la valeur des objets placés dans le sac à dos soit maximale (la plus grande possible)
Def
\(\rightarrow\) Une solution sera dite
\(\rightarrow\) La meilleure solution possible, i.e. celle dont la somme des valeurs \(v_i\) est la plus grande parmi toutes les solutions possibles, sera dite une
Animation Web⚓︎
Un exemple débranché
⚓︎
On se donne \(5\) objets et un sac à dos de poids maximal \(P_{max}=30\) kg
Objets | A | B | C | D | E |
---|---|---|---|---|---|
Valeur \(v_i\) | 11 | 6 | 8 | 15 | 7 |
Poids \(p_i\) | 16 | 4 | 9 | 12 | 8 |
Notation : On note \(x\) une variable telle que, pour chaque objet \(i\):
- \(x_i=1\) si on place l'objet \(i\) dans le sac à dos
- \(x_i=0\) sinon
Débranché
Avec les notations précédentes:
- Traduisez sous forme d'une inégalité le fait que le poids total des objets retenus ne doit pas dépasser \(P_{max}\)
- Quelle somme doit être maximale?
- Déterminer manuellement (
) une solution optimale.
Heuristiques Gloutonnes pour le Problème du Sac à Dos⚓︎
On décide de résoudre ce problème avec une heuristique gloutonne. Le principe d’un Algorithme Glouton est de faire le meilleur choix pour prendre le premier objet, puis le meilleur choix pour prendre le deuxième, et ainsi de suite. Mais que faut-il entendre par meilleur choix ? On retrouve bien là toute la notion d'Heuristique, plusieurs heuristiques étant envisageables:
Heuristique 1 Est-ce prendre l’objet qui a la plus grande valeur?Heuristique 2 l’objet qui a le plus petit poids?Heuristique 3 l’objet qui a le rapport valeur/poids le plus grand ?
Dans ce cas, on dit que l'objet est plusefficace .
Il faut encore départager ces \(3\) heuristiques.
Débranché
On reprend les 5 objets de l'Exercice précédent:
Objets | A | B | C | D | E |
---|---|---|---|---|---|
Valeur \(v_i\) | 11 | 6 | 8 | 15 | 7 |
Poids \(p_i\) | 16 | 4 | 9 | 12 | 8 |
On décide de comparer les différentes heuristiques gloutonnes suivantes:
-
Heuristique 1 On choisit à tout instant l'objet restant ayant le plus de valeur.Objets \(\,\) \(\,\) \(\,\) \(\,\) \(\,\) Valeur \(v_i\) \(\,\) \(\,\) \(\,\) \(\,\) \(\,\) Poids \(p_i\) \(\,\) \(\,\) \(\,\) \(\,\) \(\,\) - Objets retenus:
_____________________________________________________________________________________
- Poids :
_____________________________________________________________________________________________
- Valeurs :
___________________________________________________________________________________________
- Objets retenus:
-
Heuristique 2 On choisit à tout instant l'objet restant ayant le poids le plus faible.Objets \(\,\) \(\,\) \(\,\) \(\,\) \(\,\) Valeur \(v_i\) \(\,\) \(\,\) \(\,\) \(\,\) \(\,\) Poids \(p_i\) \(\,\) \(\,\) \(\,\) \(\,\) \(\,\) - Objets retenus:
_____________________________________________________________________________________
- Poids :
_____________________________________________________________________________________________
- Valeurs :
___________________________________________________________________________________________
- Objets retenus:
-
Heuristique 3 On choisit à tout instant l'objet restant le plus efficace, i.e. celui dont le rapport \(\,\, efficacité=\dfrac {valeur}{poids}\) est le plus grandObjets \(\,\) \(\,\) \(\,\) \(\,\) \(\,\) Valeur \(v_i\) \(\,\) \(\,\) \(\,\) \(\,\) \(\,\) Poids \(p_i\) \(\,\) \(\,\) \(\,\) \(\,\) \(\,\) - Objets retenus:
_____________________________________________________________________________________
- Poids :
_____________________________________________________________________________________________
- Valeurs :
___________________________________________________________________________________________
- Objets retenus:
-
Laquelle des 3 heuristiques précédentes vous semble être la meilleure dans le cas particulier de cet exemple?
- Comparez-les à la solution optimale de l'Exercice précédent. Que peut-on en déduire quant à l'optimalité d'un algorithme glouton?
Préparation de l'Algorithme Glouton
Nous verrons dans la prochaine partie que l'algorithme glouton fait la supposition que les données sont déjà triées, selon l'heuristique choisie. C'est le but de cet exercice: trier les données.
-
En Python, Écrire une fonction
efficacites(objets=[nom,v,p]:list)->[nom,v,p,eff]:list
qui accepte en entrée une liste de listesobjets=[nom,v,p]
contenant:- la sous-liste des
noms
des objets, - la sous-liste de leurs valeurs
v
, - et la sous-liste de leurs poids
p
,
et qui renvoie en sortie une liste des mêmes objets, augmentée de la sous-liste
eff
des efficacités, à calculer pour chaque objet. - la sous-liste des
-
En Python, Écrire une fonction
tri_insertion(objets=[nom,v,p,eff]:list,heuristique:str)->[nom,v,p,eff]:list
qui accepte en entrée la liste de listes non triéeobjets=[nom,v,p,eff]
contenant:- la sous-liste des
noms
des objets, - la sous-liste de leurs valeurs
v
, - la sous-liste de leurs poids
p
, - la sous-liste de leurs efficacités
eff
, - ainsi que l'
heuristique:str
choisie (parmi les 3 valeurs possibles: 'valeurs', 'poids' ou 'efficacite'),
et renvoyant en sortie la liste de listes
[nom,v,p,eff]
triée par insertion selon l'heuristique choisie. - la sous-liste des
Principe de l'Algorithme Glouton pour le problème du Sac à Dos⚓︎
Notations de l'algorithme glouton⚓︎
n
désigne le nombre d'objets- la liste
objets=[noms,v,p,eff]
contient plusieurs sous-listes:- la sous-liste
noms
des noms desn
objets - la sous-liste
v
des valeurs desn
objets - la sous-liste
p
des poids desn
objets - la sous-liste
eff
des efficacités desn
objets
- la sous-liste
- On note
x
la liste de0
et de1
, désignant si un objet sera retenu dans le sac à dos ou pas, par exemple:x[3]=1
voudra dire que l'on choisit de retenir l'objet d'indice 3 pour le stocker dans le sac à dos.x[3]=0
voudra dire le contraire: on ne retient pas cet objet pour être placé dans le sac à dos.
Principe de l'Algorithme Glouton itératif pour le Problème du Sac à Dos⚓︎
Pré-Supposition
(cf Exercice précédent) On suppose, avant même de commencer l'algorithme glouton itératif, que la sous-liste des
objets=[nom,v,p,eff]
correspondant à l'heuristique gloutonne choisie (v
,p
oueff
), soit déjà triée.- Initialiser le
poidsCourant
à 0 (des objets actuellement placés dans le sac à dos). Initialiser la listex
des objets retenus à[0,0..,0]
- Pour chacun des objets, si l'ajout de l'objet suivant (dans l'ordre de l'heuristique gloutonne choisie) ne provoque pas un dépassement de poids, alors on retient cet objet en paramétrant convenablement la variable
x
pour cet objet, sinon on ne le retient pas - A la fin du parcours de tous les objets, la varaible
x
contient les objets retenus
Remarque
Remarquons que cette méthode correspond bien à une Heuristique Gloutonne, car elle se résume à commencer par choisir systématiquement l'objet le plus gros selon l'heuristique choisie.
Pseudo-code de l'Algorithme Glouton Itératif
En pseudo-code, Proposer un algorithme glouton itératif pour le problème du Sac à Dos.
Implémentation Python⚓︎
Implémentation en Python
- Dans le langage de programmation Python, Proposer un algorithme glouton itératif contenant une fonction
sacADosGlouton(objets=[nom,v,p]:list,heuristique:str)->x:list
qui renvoie la liste des objets retenus. - Comment calculer la valeur de la solution, i.e. le nombre d'objets retenus?
- Comment calculer la solution, i.e. le détails de quels objets ont été retenus?
- Étudier la Terminaison de cet algorithme glouton itératif pour le problème du Sac à Dos
- Étudier la Complexité de cet algorithme glouton itératif pour le problème du Sac à Dos
Une Application : des Vidéos sur une clé USB⚓︎
Nous disposons d’une clé USB qui est déjà bien remplie et sur laquelle il ne reste que 5 Go de libre. Nous souhaitons copier sur cette clé des fichiers vidéos pour l’emporter en voyage. Chaque fichier vidéo a un nom, une taille et une durée. La durée n’est pas proportionnelle à la taille car les fichiers sont de format différents, certaines vidéos sont de grande qualité, d’autres sont très compressées. Le tableau qui suit présente les fichiers disponibles avec les durées données en minutes.
Comme nous sommes en vacances... Le problème est de maximiser la durée des films emmenés, mais avec une Taille Maximale de \(5 \, Go\).
Fichier | Durée | Taille |
---|---|---|
Vidéo \(1\) | \(114 \,\) | \(4,57\) Go |
Vidéo \(2\) | \(32\) | \(630\) Mo |
Vidéo \(3\) | \(20\) | \(1,65\) Go |
Vidéo \(4\) | \(4\) | \(85\) Mo |
Vidéo \(5\) | \(18\) | \(2,15\) Go |
Vidéo \(6\) | \(80\) | \(2,71\) Go |
Vidéo \(7\) | \(5\) | \(320\) Mo |
Représentation des données
Lister plusieurs manières de représenter les données en Python
Force Brute⚓︎
Limites de l'Algorithme Glouton⚓︎
Nous avons vu que l'algorithme Glouton ne donne, en général, pas une solution optimale. On pourrait penser qu'une bonne idée serait de parcourir toutes les solutions, on pourrait ainsi au moins déterminer la solution optimale (Force Brute). Il est un fait connu que c'est une très mauvaise idée du point de vue de la complexité (en temps). Voyons néanmoins comment on pourrait faire cela.
Force Brute⚓︎
Sur le papier, le principe est simple, il faut tester tous les cas possibles. La mise en oeuvre pratique l’est moins. Comment obtenir tous les cas sans les répéter et sans en oublier un ? Cette question pose la difficulté principale. Une méthode est d’associer le chiffre \(1\) à un fichier s’il est choisi et le chiffre \(0\) sinon. Nous obtenons ainsi un nombre entier écrit en binaire avec \(7\) chiffres.
Exp
- Le nombre \(1001100\) signifie que nous avons choisi les fichiers \(1\), \(4\) et \(5\).
- Le nombre \(1111111\) signifie que nous avons choisi tous les fichiers.
- A chaque nombre correspond exactement une possibilité pour construire une partie de l’ensemble des \(7\) fichiers.
- Il apparaît alors que le nombre total de cas est \(2^7\) puisqu’avec \(7\) chiffres nous pouvons écrire exactement \(2^7\) nombres.
Ex
- Écrire une fonction Python
int_to_bin(n:int,nbits:int)->ch:str
qui convertit un nombre entiern
en binaire codé surnbits
bits. On pourra utiliser, ou pas, la fonction native de Pythonbin
- Écrire une fonction Python
ens_des_parties(ensemble:list de tuples)->parties:list
qui prend en paramètres un ensemble de notre problème des 7 fichiers, et renvoie l'ensemble des parties pouvant être consituées. - Écrire une fonction Python
duree_totale(liste:list)->d:int
qui prend en paramètres la liste des vidéos, et qui renvoie la durée totale de la liste - Écrire une fonction Python
taille_totale(liste:list)->t:int
qui prend en paramètres la liste des vidéos, et qui renvoie la taille totale de la liste - Écrire une fonction Python
recherche(ense_parties:list,contrainte:int)->solution:list, duree_max:int
qui prend en paramètres un ensemble de parties et la contrainte, et renvoie la partie correspondant au meilleur choix satisfaisant la contrainte après avoir parcouru toutes les parties. - Écrire une fonction Python
force_brute(fichiers:list,taille_max:int)->recherche(parties,taille_max)
qui prend en paramètres la liste desfichiers
et lataille_max
, et qui renvoie le résultat derecherche(parties, taille_max)
. - Conclure