Ce document étudie le problème de la sous-séquence de somme maximale. Ce problème est intéressant parce qu’il existe nombre d’algorithmes pour le résoudre et la complexité (en nombre d’opérations de somme) de ces algorithmes varie considérablement. Seulement deux algorithmes seront abordés, un prochain document présentera l’algorithme le plus efficace (cf. programmation dynamique).
Présentation
tab[1..n]
d’entiers (positifs et négatifs), déterminer la valeur maximale du sous-tableau tab[g..h]
donnant la plus grande somme de tous les sous-tableaux contigus de tab
.
Pour plus de commodité, la sous-séquence de somme maximale est 0 si tous les entiers sont négatifs.
Exemples
- Pour le tableau
tab = [-2, -5, 6, -2, -3, 1, 5, -6]
, la sous séquence de somme maximale est[6, -2, -3, 1, 5]
et sa somme est 7. - Pour le tableau
tab = [0, 1, 2, -2, 3, 2]
, la sous séquence de somme maximale est[1, 2, -2, 3, 2]
et sa somme est 6. - Pour le tableau
tab = [1, -2, 3, 10, -4, 7, 2, -5]
, la sous séquence de somme maximale est[3, 10, -4, 7, 2]
et sa somme est 18.
Paradigme « Brute force »
- On envisage dans un premier temps un algorithme basé sur le paradigme « Brute force » : on évalue la somme de chaque sous-tableau (parmi les $n(n + 1)/2$ sous-tableaux possibles) et à chaque évaluation on mémorise la somme maximale.
Écrire le code de la fonction
sous_tab_max
dont la spécification est :
|
|
Tester cette fonction.
Réponse
|
|
- Quelle est la complexité de cette fonction ?
Réponse
On retrouve deux boucles imbriquées dans la fonction, la complexité est donc en $O(n^2)$.
Paradigme « Diviser pour régner »
Dans la suite, on cherche à mettre en œuvre le paradigme « Diviser pour régner ».
Le tableau initial est scindé en deux parties de tailles à peu près égales (selon que $n$ est pair ou impair) : la plus grande somme se trouve soit dans le sous-tableau $B$ de droite, soit dans le sous-tableau $A$ de gauche, soit à cheval sur les deux sous-parties. Dans ce dernier cas elle est constituée d’une plus grande somme de la partie gauche se terminant à la fin de la partie gauche (c.-à-d. en $m$), et d’une plus grande somme de la partie droite commençant au début de la partie droite (c’est à dire en $m+1$).
La procédure est récursive. Pour « sortir » des appels récursifs, il est nécessaire de rencontrer un « couple de données-paramètres » (transmis à l’appel) dont la solution est triviale. C’est le cas si le tableau est composé d’au plus un élément.
- Écrire le code de la fonction
somme_max
dont la spécification est :
|
|
Remarque
Ne pas effectuer le calcul de la somme maximale se trouveant dans la séquence à cheval sur les deux sous-parties. Ce calcul doit être effectué par un appel à la fonction max_sous_tab
définie ci-dessous.
Réponse
|
|
- Écrire le code de la fonction
max_sous_tab
dont la spécification est :
|
|
Réponse
|
|
- Quelle est la complexité de la fonction
somme_max
?