On cherche à déterminer la somme maximale obtenue en parcourant la grille :
depuis la case en haut à gauche (case d'origine)
jusqu'à la case en bas à droite (case finale)
en ne faisant que des déplacements vers la droite ou vers le bas .
Dans l'exemple ci-dessus, la somme maximale vaut \(18\). Elle est obtenue en faisant le parcours \(3\)\(5\)\(9\)\(1\).
Ces grilles sont représentées en machine par des listes de listes Python. La grille précédente est ainsi représentée par :
🐍 Script Python
grille=[[3,5,6],[4,9,1]]
La valeur de la case finale s'obtient en faisant grille[1][2]. On dit que cette case a pour coordonnées (1,2).
On demande donc d'écrire la fonction somme_maximale qui prend en paramètre la liste de listes grille et renvoie la somme maximale que l'on peut obtenir en effectuant le parcours.
L'idée principale est de compléter un tableau maxis de mêmes dimensions que la grille et contenant, dans chaque cellule de coordonnées (i, j), la somme maximale des chemins partant de l'origine et allant jusqu'à la cellule de coordonnées (i, j).
Dans l'exemple précédent, ce tableau est :
🐍 Script Python
maxis=[[3,8,14],[7,17,18]]
On constate que le chemin maximal entre l'origine et la case de coordonnées (0,2) a pour valeur 14. Il s'agit du chemin 356.
On propose trois versions de cette fonction :
une version récursive utilisant la mémoïsation et complétant le tableau maxis récursivement depuis la case finale,
une version itérative complétant le tableau maxis depuis la case d'origine,
une seconde version itérative optimisant l'espace mémoire.
Dans le cas général où la case étudiée n'est ni sur la première ligne, ni sur la première colonne, il est intéressant de remarquer qu'il n'y a que deux manières d'arriver à cette position : en venant soit de la case du dessus soit de celle de gauche. Le chemin le plus intéressant est celui qui est associé à la somme la plus importante.
Version récursive
Dans cette version on utilise une fonction annexe somme_maximale_rec qui prend en paramètres les coordonnées i et j d'une case, calcule et renvoie la valeur de maxis[i][j] (c'est à dire la somme maximale que l'on peut obtenir en allant de l'origine à la case (i, j)).
Le tableau maxis est initialisé dans la fonction principale somme_maximale. On pourra le compléter initialement avec la valeur None afin de facilement distinguer les cellules déjà calculées de celles restant à calculer.
Cette version remonte les chemins depuis la case finale (en bas à droite) jusqu'à la case d'origine. Chaque pas « en arrière » correspond à un appel récursif.
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Entrer ou sortir du mode "deux colonnes" (Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran" (Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
On cherche toujours à compléter le tableau maxis mais cette fois-ci on part de l'origine de la grille et on progresse, colonne par colonne et ligne par ligne jusqu'à atteindre la case finale.
Le tableau maxis est initialisé aux bonnes dimensions en ne contenant que des valeurs nulles.
La première ligne et la première colonne de cette liste sont traitées à part.
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Entrer ou sortir du mode "deux colonnes" (Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran" (Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Là encore, il s'agit d'une version partant de la case d'origine et progressant jusqu'à la case finale.
On remarque toutefois ici que le calcul de maxis[i][j] ne fait intervenir que les valeurs du dessus et de gauche.
Il n'est donc pas nécessaire de stocker en mémoire l'ensemble du tableau maxis. On peut travailler avec une simple ligne ligne_maxis aussi large que la grille.
Cette liste prend initialement comme valeurs les sommes maximales de chemins reliant l'origine à chacune des cases de la première ligne de la grille.
On met ensuite à jour cette liste ligne par ligne jusqu'à ce qu'elle contienne les valeurs de la dernière ligne. Pour ce faire on crée une liste temporaire qui correspondra à la ligne suivante. On la complète en utilisant les valeurs de la ligne actuelle. Cette ligne étant complète, on remplace ligne_maxis par cette nouvelle ligne.
###(Dés-)Active le code après la ligne # Tests (insensible à la casse) (Ctrl+I)
Entrer ou sortir du mode "deux colonnes" (Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran" (Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
# Tests
(insensible à la casse)(Ctrl+I)
(Alt+: ; Ctrl pour inverser les colonnes)
(Esc)