Somme d'un sous-ensemble⚓︎
Étant donné un ensemble \(E\) d'entiers positifs et un entier naturel \(s\), on demande s'il existe un sous-ensemble de \(E\) dont la somme des éléments est égale à \(s\).
On appelle ensemble vide l'ensemble qui ne contient aucun élément et on le note en général \(\emptyset\). L'ensemble vide est un sous-ensemble de n'importe quel ensemble \(E\) et la somme de ses éléments vaut \(0\).
Méthode par force brute : on teste tous les sous-ensembles de \(E\).
Le problème avec cette méthode est que si \(n\) est le nombre d'éléments de \(E\), alors le nombre de sous-ensembles de \(E\) est \(2^n\).
Avec le calcul des sommes de chaque sous-ensemble, on obtient un coût total de l'ordre de \(n\times 2^n\).
Ce coût est rédhibitoire. Par exemple, avec \(n=40\), le coût est d'environ \(40\times 2^{40} \simeq 4\times 10^{13}\). Donc si une machine effectue une opération en \(10^{-7}\) s, il faudra
environ \(4\times 10^6\) s pour explorer tous les cas, soit environ 1000 heures !
On va donc utiliser la programmation dynamique.
Programmation dynamique⚓︎
Un ensemble de nombres est représenté par une liste en Python, par exemple [4, 1, 8, 2]
.
Définition des sous-problèmes
Pour chaque élément d'indice i
, nous avons une prise de décision entre deux possibilités:
-
soit on choisit cet élément d'indice
i
et on continue récursivement avec les éléments restants et la somme restante; -
soit on ne le choisit pas et on continue récursivement avec les éléments restants et la même somme.
Les cas de base:
-
la somme à obtenir est nulle et le sous-ensemble est trouvé,
-
il n'y a pas d'élément à choisir ou la somme à obtenir est négative.
On utilise un dictionnaire pour mémoriser les solutions des sous-problèmes dans une approche descendante. Une clé du dictionnaire est un couple (s, i)
qui représente
le sous-problème obtenir la somme s
en considérant les éléments à partir de l'indice i
, la valeur associée étant True
ou False
.
Compléter le code de la fonction somme_possible
qui prend en paramètres une liste ens
représentant un ensemble de nombres, un entier positif s
, un indice i
,
un dictionnaire memo
et qui renvoie True
s'il existe un sous-ensemble de nombres dont la somme des éléments vaut s
et False
sinon.
Exemple
>>> nombres = [4, 1, 8, 2]
>>> somme_possible(nombres, 7, 0, {})
True
Le sous-ensemble dont la somme des éléments vaut 7 est \(\{ 4, 1, 2 \}\).
# Tests
(insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)