informatique (tronc commun des prépas scientifiques) · Chapitre 18 · Exercice de TD
La partition équilibrée
La programmation dynamique · niveau 2
Énoncé
On souhaite diviser un ensemble d'entiers positifs, par exemple , en deux sous-ensembles dont les sommes sont les plus proches possibles. (a) Formuler la récurrence booléenne définissant si une somme peut être formée par un sous-ensemble d'éléments. (b) Implémenter cet algorithme en Python, identifier la meilleure somme (où est la somme totale) et reconstruire le sous-ensemble correspondant. (c) Exprimer sa complexité et préciser le terme "pseudo-polynomial".
Corrigé
(a) Pour chaque élément du tableau, la somme est atteignable si elle l'était déjà avant de considérer , ou si la somme était atteignable (en choisissant d'intégrer ). (b)
def partition_equilibree(t: list) -> tuple:
S = sum(t)
atteignable = [True] + [False] * (S // 2)
temoin = [None] * (S // 2 + 1) # Stocke l'élément ayant permis d'atteindre la somme s
for x in t:
# Parcours à rebours pour éviter de réutiliser le même élément plusieurs fois
for s in range(S // 2, x - 1, -1):
if not atteignable[s] and atteignable[s - x]:
atteignable[s] = True
temoin[s] = x
# Trouver la plus grande somme atteignable inférieure ou égale à S/2
meilleur = max(s for s in range(S // 2 + 1) if atteignable[s])
# Reconstruction
paquet, s = [], meilleur
while s > 0:
paquet.append(temoin[s])
s -= temoin[s]
return (paquet, meilleur, S - meilleur)
Pour , la somme totale est (cible ). L'algorithme renvoie le paquet [13, 5] (somme ) contre les éléments restants [8, 4, 6] (somme ), réalisant un équilibre parfait. (c) Complexité temporelle : , mémoire : . La complexité est polynomiale par rapport à la valeur de , mais exponentielle par rapport à son nombre de bits. C'est un algorithme pseudo-polynomial : très rapide pour des valeurs de sommes modérées, mais inefficace si les entiers contiennent un très grand nombre de chiffres.