Vous êtes sur la page 1sur 12

Introduction

Le problème du sac à dos (aussi connu sous le nom de "Knapsack"), est un


problème d'optimisation combinatoire largement connu en informatique. Dans
notre etude, vous apprendrez comment résoudre le problème du sac à dos en
utilisant la programmation dynamique. Le problème du sac à dos peut être
énoncé comme suit :
Définition
Étant donné un ensemble d'articles différents, chacun avec une valeur et un
poids associés, déterminez quels articles vous devriez choisir afin de maximiser
la valeur des articles sans dépasser la capacité de votre sac à dos.
Concrètement, imaginez que nous avons l'ensemble suivant d'articles de
valeur, et le sac à dos donné.
Exemple
Supposons que vous ayez un ensemble de 5 articles :
Article 1 Article 2 Article 3 Article 4 Article 5
valeur 50fcfa 100fcfa 30fcfa 20fcfa 30fcfa
poids 4 kg 8 kg 3 kg 5 kg 2kg

Si la limite de poids de votre sac à dos est de 10 kg, quelle est la solution
optimale ? C'est-à-dire, quels articles devriez-vous emporter avec vous ?
Dans ce cas, la solution est claire. On prendrait le deuxième et le dernier article,
obtenant une valeur de 130 FCFA tout en respectant exactement la limite de
poids. Nous atteignons la valeur maximale possible sans violer la contrainte du
problème.
Cependant, l'évaluation de toutes les possibilités est très peu pratique en
général, c'est pourquoi nous aimerions savoir s'il existe une meilleure façon
d'aborder ce problème. En fait, il y en a un, et nous verrons un algorithme dans
la suite.
problème
gina voyage avec Tom dans le désert, et elle portera toute leur nourriture. Elle
peut porter un maximum de 9,5 kg et a 5500 cm3 de provisions dans son sac.
Gina peut choisir parmi les fournitures suivantes :

produits poids volumes calories


alimentaire
mangues 240 g 400 cm3 900
Chips de pommes 135 g 400 cm3 650
de terre
Bœuf séché 2800 g 1500 cm3 5000
Amandes 410 g 410 cm3 950
Pommes 182 g 190 cm3 95

Quel est le plus grand nombre de calories qu'elle peut apporter avec elle,
compte tenu de ses contraintes ?
NB: Gina peut en apporter autant qu'elle le désire pour chacun des articles ci-
dessus.

Résolution du problème

Ce problème peut être résolu en utilisant une simple récursivité et un tableau


bidimensionnel.
Pour commencer, nous devrions trouver une représentation pratique pour
notre problème et la définir soigneusement. Nous pouvons dire que nous avons
un ensemble d'articles n , chaque article a une valeur vi et un poids wi , et
notre sac a une limite de poids total de w.
Maintenant, nous construisons une table n×w :
0 1 2 3 … … … w-1 w
0
1
2

n-1
n

Table1

Chaque cellule du tableau a la valeur t[i,j], où i représente la ième ligne et j


représente la jème colonne.
t[i,j] est la valeur maximale que nous pouvons obtenir en utilisant n'importe
quelle combinaison de l'ensemble des premiers éléments i de la liste sans
dépasser un certain poids j . Avec cela, nous pouvons déjà identifier une
récursivité pour notre table :
Définition
Récusions pour le problème du sac à dos :

t[i − 1, j] 𝑠𝑖 𝑤𝑖 ˃𝑗
t[i,j] ={
max(𝑡[𝑖 − 1, 𝑗], 𝑡[𝑖 − 1, 𝑗 − 𝑤𝑖] + 𝑣𝑖) 𝑠𝑖 𝑤𝑖 ≤ 𝑗.

Essayons d'interpréter cette récursivité


Supposons que vous ayez une certaine valeur t[i-1,j] dans votre tableau, ce qui
signifie que la valeur maximale que vous pouvez obtenir en utilisant n'importe
quelle combinaison des premiers éléments i -1 de votre liste et la somme du
poids de chaque élément ne dépasse pas j . Si nous pouvons le faire, il est
évident que nous pouvons faire la même chose en utilisant les premiers
éléments i de notre liste. Nous trouvons donc le premier cas de notre
récursivité, ce qui est assez simple :
t[i,j]= t[i-1,j] 𝑠𝑖 𝑤𝑖 ˃𝑗

Et comment fonctionne le deuxième cas de récursivité ?


Étant donné wi ≤ j, nous pouvons dire que t[i,j]= t[i-1,j-wi]+vi parce que si nous
pouvons obtenir une certaine valeur t[i-1,j-1] en utilisant les premiers éléments
i-1 de la liste, nous pouvons aussi ajouter le ième élément de la liste au sac à dos
et il ne dépassera pas la limite actuelle, parce qu'avant d'obtenir le ième
élément, le poids actuel est j-wi, donc si on ajoute le ième élément, le poids
actuel deviendra j-wi+wi=j, donc on maintient le poids actuel égal à la limite de
poids et la nouvelle valeur sera t[i-1,j-wi] plus la valeur de l'élément vi, alors
t[i,j] devient t[i-1,j-wi]+vi. Néanmoins, ce n'est pas toujours la meilleure option.
Si la valeur de t[i-1,j] est plus grande, nous utiliserons cette valeur au lieu de
t[i-1,j-wi] . Rappelez-vous que t[i,j] ne calcule que la valeur maximale, donc
nous choisirons toujours la meilleure option.

Enfin, la fonction max() évalue quelle est la meilleure option (c'est-à-dire


qu'elle trouve la plus grande valeur).

Pour trouver la plus grande valeur possible, il suffit d'obtenir t[n,W] (c'est-à-
dire la valeur maximale possible en utilisant les n articles de notre liste alors
que le poids total est inférieur à la capacité W de notre sac.
Théorème :
Dans ce problème, nous employons une matrice de hauteur n et de largeur w,
et notre algorithme passe par chaque cellule une fois, ce qui fait n×w
opérations au total. Par conséquent, la complexité du problème du sac à dos
est O(n×w).
Algorithme avec python

# n:number of items
# v[i]:value of the i-th item, w[i]: weight of the i-th item
# W = backpack capacity

knapsack(n,v,w,W)
for j=0 to j=W
t[0, j]=0
for i=1 to n
for j=0 to W
if w[i]>j
t[i, j]=t[i - 1, j]
else
t[i, j] = max(t[i - 1, j], t[i - 1, j - w[i]]+v[i])
return t[n][W]

Nous allons maintenant résoudre le premier exemple :


Exemple
On vous donne un ensemble de cinq éléments I1, I2, I3, I4, I5 et chacun a une
valeur et un poids correspondants entre parenthèses [vi,wi] :
I1=[5,4] ; I2=[10,8] ; I3=[3,3] ; I4=[2,5] ; I5=[3,2].
Quelle est la valeur maximale que vous pouvez obtenir en sachant que la limite
de poids du sac à dos est de 10 ?
1-Commençons à remplir notre table
Nous savons que toutes les cellules de la première rangée sont nulles, alors :
0 0 0 0 0 0 0 0 0 0 0 0
1
2
3
4
5

Tableau 2

En utilisant la récursivité, nous savons que t=[1,0]= t[1,1]= t[1,2]= t=[1,2]=


t[1,3]= 0, mais lorsque j=4, t=[1,j] =t[1,4]=5 Cela se produit parce qu'à ce point
w[i]≤j, le poids de l'article est w[i]=4 et j=4, de sorte qu'il satisfait à la condition
pour le deuxième cas de récursivité. Nous le savons bien :

t=[i-1,j]= t[0,4]=0
et que
t=[i-1,j-w[i]]+vi= t[0,0]+vi=0+5=5.

Par conséquent, le maximum ici est de 5, puis t=[i,j]= t[1,4]=5 . En faisant la


même chose pour j=5 à j=10, nous obtiendrons aussi 5, de sorte que notre
tableau devient :
0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 5 5 5 5 5 5 5
2
3
4
5

Tableau 3

Maintenant, i=2 Nous continuerons à faire le même processus. En faisant les


calculs, nous verrons que t=[2,j]=0 de j=0 à j=3, t=[2,j]=5, de j=4 à j=7. Lorsque
j=8,
w[i] ≤j, nous devrons donc analyser les deux cas :
t=[i-1,j]= t[1,8]=5.
t=[i-1,j-w[i]]+vi= t=[1,0]+vi=0+10=10
La deuxième option est la meilleure.

t=[i,j]= t=[2,8]=10
En faisant la même chose jusqu'à ce que nous terminions la rangée, nous
obtenons
0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 5 5 5 5 5 5 5
2 0 0 0 0 5 5 5 5 10 10 10
3
4
5

Tableau 4

Il suffit de continuer à utiliser la récursivité pour remplir les troisième et


quatrième lignes, jusqu'à ce que vous arriviez à la dernière :

0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 5 5 5 5 5 5 5
2 0 0 0 0 5 5 5 5 10 10 10
3 0 0 0 3 5 5 5 8 10 10 10
4 0 0 0 3 5 5 5 8 10 10 10
5

Tableau 5

Quand vous atteignez t=[5,9] vous verrez


t=[i-1,j]= t=[4,9]=10
Et
t=[i-1,j-w[i]]+vi= t=[5,9]+vi=8+3=11
Pour la dernière cellule
t=[i-1,j]= t=[5,9]=10
Et
t=[i-1,j-w[i]]+vi= t=[5,8]+vi=10+3=13.
Par conséquent t=[i,j]= t=[5,10]=13.
Voici notre tableau complet :

0 0 0 0 0 0 0 0 0 0 0 0
1 0 0 0 0 5 5 5 5 5 5 5
2 0 0 0 0 5 5 5 5 10 10 10
3 0 0 0 3 5 5 5 8 10 10 10
4 0 0 0 3 5 5 5 8 10 10 10
5 0 0 3 3 5 6 8 8 10 11 13

La valeur maximale que nous pouvons obtenir est t=[n,W] t=[5,10]=13, ce qui
peut être obtenu en utilisant le deuxième et le dernier élément. En faisant cela,
le poids total sera de 10 (C'est égal à la capacité, qui est de 10) et la valeur
totale sera de 13.

Voici un exemple de code que vous pouvez utiliser pour résoudre le problème :

Algorithme avec python


1 #include <iostream>
2 #include <cstring>
3
4 /*Knapsack problem*/
5
6 //W=Backpack capacity
7 //w[i]=i-th item's weight
8 //v[i]=i-th item's value
9
10 //Compares two values and returns the bigger one
11 int maximum(int a,int b){
12 if(a>=b) return a;
13 else return b;
14 }
15
16 using namespace std;
17
18 int main()
19 {
20 int W, v[100],w[100];
21 int i,j,n;
22 int table[100][10000];
23
24 //Reads W and the number of items n
25 cin>>W>>n;
26
27 //Reads the weight and the value of each item
28
29 for(i=1;i<=n;i++) {
30 cin>>w[i]>>v[i];
31 }
32
33 //Make every single cell in the first row equal to zero
34
35 for(j=0;j<=W;j++) table[0][j]=0;
36
37 // Fills the table
38
39
40 for(i=1;i<=n;i++)
41 for(j=0;j<=W;j++){
42 //First case of the recursion
43 if(w[i]>j) table[i][j]=table[i-1][j];
44 //Second case
45 else table[i][j]=maximum(table[i-1][j],table[i-1][j-w[i]] + v[i]);
46
47 }
48
49 cout<<"\n";
50
51 //Shows the table
52 for(i=0;i<=n;i++){
53 cout<<"\n";
54 for(j=0;j<=W;j++){
55 cout<<table[i][j]<<" ";
56 }
57 }
58
59 //Prints the answer
60 cout<<"\nMaximum value:\n";
61
62 cout<<table[n][W];
63
64 cout<<"\n\n";
65
66 return 0;
67 }
Domaines d'application
Bien qu'énoncé et simplement résolu, le problème du sac à dos peut être
cartographié directement, s'il n'est pas utilisé comme prototype pour de
nombreux problèmes pratiques. Les applications directes comprennent

-Une compagnie maritime essayant d'emballer autant de volume de colis


dans un avion de transport sans casser la capacité de poids.
-Le désir d'une équipe sportive professionnelle de bâtir une équipe qui
répond à diverses projections statistiques sans dépasser le plafond
salarial.
-Le besoin dolent de satisfaire les besoins nutritionnels quotidiens tout
en maintenant un volume donné de poudre par portion.

Vous aimerez peut-être aussi