Chapitre 5. Récursivité
Activités de découverte
Objectifs. Découvrir les notions centrales à la récursivité : cas de base, appels récursifs, empilement et dépilement d’une pile d’appels, profondeur de récursivité.
Cours. La méthode diviser pour régner et le tri-fusion
Objectifs. Découvrir le principe de la méthode diviser pour régner pour la résolution de problème en informatique. Application aux problèmes des tours de Hanoï et au tri fusion.
Regarder cette vidéo qui aborde l’ensemble des notions au programme puis se tester à l’aide du quizz proposé après la vidéo.
Time codes pour se repérer dans la vidéo
Time code | Partie |
---|---|
00:14 | 0. Introduction |
00:48 | \quad0.1 Analogie de l’arche en pierre |
02:10 | \quad0.2 La méthode diviser pour régner |
03.33 | 1. Exemple 1. Les tours de Hanoï |
03:38 | \quad1.1 Présentation du problème |
06:41 | \quad1.2 Questions pour diviser et régner |
07:19 | \quad1.3 Réponses pour les tours de Hanoï |
08:35 | \quad1.4 Fonction Python |
11:34 | 2. Exemple 2. Le tri fusion |
12:00 | \quad2.1 Étapes principales du tri fusion |
12:54 | \quad2.2 La fusion |
20:21 | \quad2.3 Le tri fusion |
20:27 | \quad\quad2.3.1 Fonction Python |
23:45 | \quad\quad2.3.2 Exemple |
27:44 | \quad\quad2.3.2 Complexité |
Implémentation du tri-fusion (À retenir )
La fonction fusion
La fonction fusion
est une fonction itérative qui prend en paramètres
deux tableaux triés et renvoie un tableau trié résultant de la fusion de
ces deux tableaux.
-
Le plus petit élément courant est dans
tab1
. On ajoute donc au tableau résultat l’élément courant detab1
. Il ne faut pas oublier de décaler de +1 la position courante detab1
pour passer à l’élément suivant. -
Le plus petit élément courant est dans
tab2
. On ajoute donc au tableau résultat l’élément courant detab2
. Il ne faut pas oublier de décaler de +1 la position courante detab2
pour passer à l’élément suivant. -
Cas 1. On a atteint le bout de
tab2
. Par contre, on a pas atteint le bout detab1
. Donc, on complète le tableau résultat avec le reste detab1
. L’expressiontab1[pos1:]
(la droite du tableautab1
à partir de la positionpos1
) est équivalente à la liste en compréhension[tab1[i] for i in range(pos1, len(tab1))]
. -
Cas 2. On a atteint le bout de
tab1
. Par contre, on a pas atteint le bout detab2
. Donc, on complète le tableau résultat avec le reste detab2
. L’expressiontab2[pos2:]
(la droite du tableautab2
à partir de la positionpos2
) est équivalente à la liste en compréhension[tab2[i] for i in range(pos2, len(tab2))]
.
La fonction tri_fusion
La fonction tri_fusion
est une fonction récursive qui prend en paramètre
un tableau et renvoie une copie de ce tableau triée.
-
Cas de base. Le tableau a pour longueur 1 c’est-à-dire qu’il ne comprend qu’une seule case. Dans ce cas, il n’y a rien à trier, on renvoie simplement ce tableau à une case.
-
tab1
est la moitié gauche detab
du rang0
au rang médian moins 1 c’est-à-diren//2 - 1
. On en donne ci-dessous une illlustration. Remarques. L’expressiontab[:n//2]
est équivalente àtab[0:n//2]
: on “tranche” avant la case0
et avant la casen//2
. On peut utiliser à la place la liste en compréhension :[tab[i] for i in range(0, n//2)]
. -
tab2
est la moitié droite detab
du rang médiann//2
au dernier rangn - 1
. On en donne ci-dessous une illlustration. Remarques. L’expressiontab[n//2:]
est équivalente àtab[n//2:n]
: on “tranche” avant la casen//2
et avant la “case”n
. On peut utiliser à la place la liste en compréhension :[tab[i] for i in range(n//2, n)]
.
Exercices d’application
Activité. Algorithmes de recherche récursifs
Objectifs. Implémenter des versions récursives des algorithmes de recherche linéaire et dichotomique. Utiliser des paramètres de récursivité désignant des rangs dans un tableau.
Exercice 1. Exponentiation rapide
Soit x un réel non nul. On sait que x^0 = 1 et on peut remarquer que :
-
Écrire une fonction récursive
puissance(x, n)
calculant x^n.Code à trous
-
On donne ci-dessous la définition d’une fonction
mystere(x, n)
prenant en paramètre un réelx
non nul et un entier positifn
.-
Calculer “à la main”
mystere(x, 9)
. On pourra s’aider d’un schéma pour suivre l’empilement et le dépilement des appels récursifs.Réponse
Le diagramme suivant montre l’empilement des appels récursifs successifs vers le bas puis le dépilement vers le haut avec passage de valeur d’un niveau récursivité vers le niveau supérieur. Le résultat obtenu pour
mystere(x, 9)
est donc x^9.graph TB m9["mystere(x, 9)"] --> m4["mystere(x, 4)"]; m4 --> m2["mystere(x, 2)"]; m2 --> m1["mystere(x, 1)"]; m1 --> m0["mystere(x, 0)"]; m0 -- 1 --> m1; m1 -- x fois 1 fois 1 = x --> m2; m2 -- x fois x = x^2 --> m4; m4 -- x^2 fois x^2 = x^4 --> m9; m9 -- x fois x^4 fois x^4 --> r9((x^9));
Explications détaillées (diaporama)
-
Que fait la fonction
mystere
?Réponse
mystere(x, n)
renvoie x^n. -
Combien de multiplications ont été calculées au cours de l’appel
mystere(x, 9)
. Comparer avec le nombre de multiplications calculées avec l’appelpuissance(x, 9)
. Que peut-on en conclure ?Réponse
L’appel
puissance(x, 9)
effectue toutes les multiplications de l’expression suivante c’est-à-dire 9 multiplications :\begin{align*} \underbrace{x \times x \times x \times x \times x \times x \times x \times x \times x}_{x^9 \text{(8 multiplications)}} \text{ }\times 1 \end{align*}D’après la figure de la question 2. a., l’appel
mystere(x, 9)
a nécessité le calcul e 6 multiplications.Conclusion. L’algorithme de calcul de la fonction
mystere
(exponentiation rapide) est plus économe en ressource de calcul que celui de la fonctionpuissance
. Pour x^n, on peut approximer le nombre de multiplication nécéssaire au nombre de divisons par deux successives possibles pour n c’est-à-dire \log_2(n). On pourrait donc montrer que :Fonction Complexité puissance(x, n)
{\cal O}(n) mystere(x, n)
{\cal O}(\log_2(n))
-
Exercice 2. Approximations de \pi
Le nombre \pi peut être approximé en utilisant la formule suivante, que l’on peut interpréter comme la “limite” d’une suite dont les termes successifs comprennent un nombre croissant de terme d’une somme infinie. La suite s’approche de \pi au fur et à mesure que l’on ajoute des termes à la somme :
En utilisant cette formule (appelée série de Gregory-Leibniz), on souhaite
écrire une fonction récursive pi(n)
qui se rapproche de \pi lorsque n
croît.
-
Déterminer en fonction de n l’expression du terme ajouté à l’étape n
Indications
- Les dénominateurs sont impairs c’est-à-dire de la forme 2n + 1.
- l’alternance des signes peut se régler à l’aide de (-1)^n.
Réponse
Dans la parenthèse, chaque terme est de la forme :
\begin{align*} \frac{(-1)^n}{2n + 1} &\phantom{= \dfrac{1}{1}} \end{align*}Cela fonctionne par exemple pour n = 0, n = 1 et n = 2:
\begin{align*} \frac{(-1)^0}{2\times0 + 1} &= \frac{1}{1} \\ \frac{(-1)^1}{2\times1 + 1} &= -\frac{1}{3} \\ \frac{(-1)^2}{2\times2 + 1} &= \frac{1}{5} \end{align*}En tenant compte du facteur 4 devant la parenthèse, à l’étape n, le terme à ajouter est donc :
\begin{align*} \frac{4(-1)^n}{2n + 1} &\phantom{= \dfrac{1}{1}} \end{align*} -
Établir la définition par récurrence de \text{pi}(n).
Indications mathématiques
- Le premier terme pour n = 0 est 4 \times \dfrac{1}{1} = 4.
- \text{pi}(n) se calcule à partir de \text{pi}(n - 1) en lui ajoutant le terme de l’étape n.
Réponse
\begin{align*} \left\{ \begin{array}{ll} \text{pi}(0) = 4 \quad \text{(cas de base pour }n = 0) \\ \text{pi}(n) = \text{pi}(n - 1) + \dfrac{4(-1)^n}{2n + 1} &\phantom{= \dfrac{1}{1}}, \quad \text{pour tout } n \geq 1 \quad \text{(formule de récurrence)} \end{array} \right. \end{align*} -
En déduire une implémentation Python de la fonction récursive
pi(n)
.Code à trous
Exercice 3. Tri-fusion
-
Décrire birèvement les trois étapes principales du tri-fusion.
Réponse
Le tri-fusion est un exemple d’algorithme utilisant la métode diviser pour régner.
- Étape 1. Diviser. Le tableau est divisé en son milieu en deux tableaux fils.
- Étape 2. Régner. Les tableaux fils sont triés séparément.
- Étape 3. Fusionner Les tableaux fils triés sont fusionnés de telle façon à obtenir un tableau trié.
-
Représenter sur un schéma les étapes du tri-fusion des tableaux suivants :
-
[23, 12, 4, 56, 35, 32, 42, 57, 3]
Réponse
graph TB t("[23, 12, 4, 56, 35, 32, 42, 57, 3]"); t --> t2_1("[23, 12, 4, 56]"); t --> t2_2("[35, 32, 42, 57, 3]"); t2_1 --> t3_1("[23, 12]"); t2_1 --> t3_2("[4, 56]"); t2_2 --> t3_3("[35, 32]"); t2_2 --> t3_4("[42, 57, 3]"); t3_1 ---> t4_1("[23]"); t3_1 --> t4_2("[12]"); t3_2 ---> t4_3("[4]"); t3_2 --> t4_4("[56]"); t3_3 ---> t4_5("[35]"); t3_3 --> t4_6("[32]"); t3_4 ---> t4_7("[42]"); t3_4 --> t4_8("[57, 3]"); t4_8 --> t5_1("[57]"); t4_8 --> t5_2("[3]"); t4_1 & t4_2 ---> t6_1("[12, 23]"); t4_3 & t4_4 ---> t6_2("[4, 56]"); t4_5 & t4_6 ---> t6_3("[32, 35]"); t5_1 & t5_2 --> t6_4("[3, 57]"); t4_7 ---> t7_1("[3, 42, 57]"); t6_4 --> t7_1("[3, 42, 57]"); t6_1 & t6_2 --> t8_1("[4, 12, 23, 56]"); t6_3 & t7_1 --> t8_2("[3, 32, 35, 42, 57]"); t8_1 & t8_2 --> t9("[3, 4, 12, 23, 32, 35, 42, 56, 57]")
-
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Réponse
graph TB t("[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]"); t --> t2_1("[10, 9, 8, 7, 6]"); t --> t2_2("[5, 4, 3, 2, 1]"); t2_1 --> t3_1("[10, 9]"); t2_1 --> t3_2("[8, 7, 6]"); t2_2 --> t3_3("[5, 4]"); t2_2 --> t3_4("[3, 2, 1]"); t3_1 ---> t4_1("[10]"); t3_1 --> t4_2("[9]"); t3_2 ---> t4_3("[8]"); t3_2 --> t4_4("[7, 6]"); t4_4 --> t5_3("[7]") & t5_4("[6]") t5_3 & t5_4 --> t6_2; t3_3 ---> t4_5("[5]"); t3_3 --> t4_6("[4]"); t3_4 ---> t4_7("[3]"); t3_4 --> t4_8("[2, 1]"); t4_8 --> t5_1("[2]"); t4_8 --> t5_2("[1]"); t4_1 & t4_2 ---> t6_1("[9, 10]"); t6_2("[6, 7]"); t4_3 ---> t6_5("[6, 7, 8]"); t6_2 --> t6_5; t4_5 & t4_6 ---> t6_3("[4, 5]"); t5_1 & t5_2 --> t6_4("[1, 2]"); t4_7 ---> t7_1("[1, 2, 3]"); t6_4 --> t7_1; t6_1 --> t8_1("[6, 7, 8, 9, 10]"); t6_5 --> t8_1; t6_3 & t7_1 --> t8_2("[1, 2, 3, 4, 5]"); t8_1 & t8_2 --> t9("[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]");
-
-
Expliquer en détail comment l’étape de fusion est réalisée.
Réponse
- On initialise un tableau résultat vide.
- On positionne un curseur de lecture en début de chaque tableau trié.
- On lit l’élément courant dans chaque tableau et on ajoute le plus petit dans le tableau résultat.
- On déplace le curseur d’un tableau d’un cran à chaque fois q’un élément est sélectionné dans ce tableau.
- Petit à petit on parcourt les tableaux tant que l’on a pas atteint le bout d’un des tableaux.
- Si cela se produit, il suffit d’ajouter dans le tableau résultat le reste du tableau qui n’a pas été encore visité. Cela est correct car ce tableau est trié et toute les valeurs restantes sont forcément plus grandes que les valeurs déjà ajoutées au tableau résutat.
-
Le tris vu en première (par insertion, par sélection) ont une complexité quadratique c’est-à-dire en \cal O(n^2).
-
Rappeler la compléxité du tri-fusion.
Réponse
La complexité du tri-fusion est en \cal O(n\log_2(n)).
Remarque. Cela se comprend intuitivement. À chaque profondeur de récursivité, le tableau est traité en entier ce qui représente n étapes. Il suffit donc de déterminer la profondeur maximum de récursivité pour calculer le nombre d’étape totale. La profondeur de récursivité est égale au nombre de division par deux successives que va subir le tableau. Une approximation de ce nombre est \log_2(n). Le nombre d’étapes est donc de l’ordre de n\log_2(n)
-
Estimer le temps gagné par le tri-fusion par rapport aux tris vus en première pour des tableaux de taille 4, 16, et 1024.
Réponse
Une approximation grossière du gain de temps peu s’obtenir en calculant le rapport entre les complexité :
\begin{align*} \frac{n^2}{n\log_2(n)} &= \frac{n}{\log_2(n)} \end{align*}Calculant ce rapport pour n = 4, n = 16 et n = 1024 :
\begin{align*} \frac{4}{\log_2(4)} &= \frac{4}{\log_2(2^2)} \\ &= \frac{4}{2} \\ &= 2 \\ \end{align*}\begin{align*} \frac{16}{\log_2(16)} &= \frac{16}{\log_2(2^4)} \\ &= \frac{16}{4} \\ &= 4 \\ \end{align*}\begin{align*} \frac{1024}{\log_2(1024)} &= \frac{1024}{\log_2(2^{10})} \\ &= \frac{1024}{10} \\ &= 102{,}4 \\ \end{align*}On voit que plus la taille du tableau augmente plus le tri-fusion est performant par rapport aux tris vus en première : pour un tableau de taille 4 on peut estimer que le tri-fusion est deux fois plus performant, pour un tableau de 1024, c’est une multiplication par 100 des performances !
-
Exercices type Bac
Exercice n°2 (2019, Sujet zéro, Ex. 2). Chemins dans un tableau 2D
Cette exercice porte sur la programmation en général et la récursivité en particulier.
On considère un tableau de nombres de n lignes et p colonnes. Les lignes sont numérotées de 0 à n − 1 et les colonnes sont numérotées de 0 à p − 1. La case en haut à gauche est repérée par (0\,,0) et la case en bas à droite par (n−1\,,p−1) .
On appelle chemin une succession de cases allant de la case (0\,,0) à la case (n − 1\,,p − 1) , en n’autorisant que des déplacements case par case : soit vers la droite, soit vers le bas.
On appelle somme d’un chemin la somme des entiers situés sur ce chemin. Par exemple, pour le tableau tab suivant :
4 | 1 | 1 | 3 |
2 | 0 | 2 | 1 |
3 | 1 | 5 | 1 |
- Un chemin est (0\,,0), (0\,,1), (0\,,2), (1\,,2), (2\,,2), (2\,,3) (en rouge sur le tableau) ;
- La somme du chemin précédent est 14.
- (0\,,0), (0\,,2), (2\,,2), (2\,,3) n’est pas un chemin.
L’objectif de cet exercice est de déterminer la somme maximale pour tous les chemins possibles allant de la case (0\,, 0) à la case (n−1\,,p−1) .
-
On considère tous les chemins allant de la case (0\,,0) à la case (2\,,3) du tableau tab donné en exemple.
-
Un tel chemin comprend nécessairement 3 déplacements vers la droite. Combien de déplacements vers le bas comprend-il ?
Réponse
On a représenté ci-dessous l’allure du tableau tab donné en exemple. Les cases (0\,, 0) et (2\,, 3) ont été repérées.
Un chemin allant de la case (0\,,0) à la case (2\,,3) comprend nécessairement 2 déplacements vers le bas car le tableau possède 3 lignes.
Remarque. La question ne demandait pas clairement de justifier la réponse. Dans le doute, il faut mieux le faire. Une figure est toujours appréciée pour justifier mais attention à la gestion de votre temps.
-
La longueur d’un chemin est égal au nombre de cases de ce chemin. Justifier que tous les chemins allant de (0\,, 0) à (2\,, 3) ont une longueur égale à 6.
Réponse
D’après la question précédente, un déplacement de la case (0\,, 0) à la case (2\,, 3) comprend nécessairement 2 déplacements vers le bas et 3 déplacements vers la droite. Donc au cours de ce déplacement, on visite 5 cases auxquelles il faut ajouter la case de départ. Ainsi, 6 cases sont visitées. Donc, tous les chemins allant de la case (0\,, 0) à la case (2\,, 3) ont une longueur égale à 6.
-
-
En listant tous les chemins possibles allant de (0\,,0) à (2\,,3) du tableau tab, déterminer un chemin qui permet d’obtenir la somme maximale et la valeur de cette somme.
Réponse
Un chemin qui permet d’obtenir la somme maximale est (0\,,0), (1\,,0), (2\,,0), (2\,,1), (2\,,2), (2\,,3). On l’a représenté en rouge ci-dessous :
4 1 1 3 2 0 2 1 3 1 5 1 La somme maximale est donc 4 + 2 + 3 + 1 + 5 + 1 = 16.
Remarque. Cette question semble demander de lister tous les chemins possibles mais ils sont très nombreux. Ce serait une perte de temps importante. Ici, il semble pertinent de répondre sans justifier en donnant directement la réponse. Il existe cependant une méthode permettant d’explorer tous les chemins possibles à l’aide d’un arbre binaire.
- la racine de l’arbre représente la case de départ (0\,,0) ;
- tout autre nœud correspond à une case du tableau visitée lors d’un chemin ;
- une arrête reliant un nœud à son nœud fils de gauche représente un déplacement vers le bas ;
- une arrête reliant un nœud à son nœud fils de droite représente un déplacement vers la droite ;
- une arrête reliant un nœud à un unique fils représente un éplacement obligatoire vers le bas ou la droite (cas où un bord du tableau a été atteint);
- une feuille de l’arbre a pour valeur la somme des valeurs des cases rencontrées sur le chemin reliant la racine à la feuille.
Voici l’arbre en question :
graph TB A(4) --> B(2); B --> C(3) ; C --> D(1); D --> E(5); E --> F(1); F --> G[16]; B --> H(0); H --> I(1); I --> J(5); J --> K(1); K --> L[13]; H --> M(2); M --> N(5); N --> O(1); O --> P[14]; M --> Q(1); Q --> R(1); R --> S[10]; A --> T(1); T --> U(0); U --> V(1); V --> W(5); W --> X(1); X --> Y[12]; U --> Z(2); Z --> a(5); a --> b(1); b --> c[13]; Z --> d(1); d --> e(1); e --> f[9]; T --> g(1); g --> h(2); h --> i(5); i --> j(1); j --> k[14]; h --> l(1); l --> m(1); m --> n[10]; g --> o(3); o --> p(1); p --> q(1); q --> r[11];
-
On veut créer le tableau tab2 où chaque case (i\,,j) contient la somme maximale pour tous les chemins possibles allant de (0\,,0) à (i\,,j).
-
On considère le tableau tab ci-dessous.
4 1 1 3 2 0 2 1 3 1 5 1 Compléter et recopier sur votre copie le tableau tab2 donné ci-dessous associé au tableau tab précédent.
4 5 6 ? 6 ? 8 10 9 10 ? 16 Réponse
4 5 6 9 6 6 8 10 9 10 15 16 Explications :
Case (0\,,3)
La seule façon d’arriver à cette case est par la gauche par la case (0\,,2) qui contient la somme maximale 6 dans le tableau tab2. Il faut ajouter à ce nombre le nombre contenu dans la case d’arrivée (0\,,3) du tableau tab c’est-à-dire 3. Le résultat à reporter dans le tableau tab2 est donc 6 + 3 = 9.
Case (1\,,1)
Il y a deux façons d’arriver à cette case : par la case (0\,,1) ou par la case (1\,,0). Parmi ces deux cases, la somme maximale dans tab2 est 6. Il faut ajouter à ce nombre le nombre contenu dans la case d’arrivée (1\,,1) du tableau tab c’est-à-dire 0. Le résultat à reporter dans le tableau tab2 est donc 6 + 0 = 6.
Case (2\,,2)
Il y a deux façons d’arriver à cette case : par la case (1\,,2) ou la case (2\,,1). Parmi ces deux cases, la somme maximale dans tab2 est 10. Il faut ajouter à ce nombre le nombre contenu dans la case d’arrivée (2\,,2) du tableau tab c’est-à-dire 5. Le résultat à reporter dans le tableau tab2 est donc 10 + 5 = 15.
-
À partir de cette question, on choisit de représenter les tableaux tab et tab2 par un tableau Python (type
list
) père contenant des tableaux Python (typelist
) fils. Chaque tableau fils représente une ligne du tableau. Par exemple, le tableau tab de la question précédente est représenté en Python comme suit.Justifier que si
j
est différent de0
, alors :tab2[0][j] = tab[0][j] + tab2[0][j-1]
.Réponse
tab2[0][j]
désigne la somme maximale de la case (0\,,j) qui se trouve dans la première ligne du tableau (case de départ (0\,,0) exclue carj
est différent de0
). La seule façon d’arriver à cette case est de venir de la gauche par la case (0\,,j-1) comme présenté sur la figure ci-dessous :Pour calculer
tab2[0][j]
il faut donc additionner :- la somme maximale de la case (0\,,j-1) c’est-à-dire
tab2[0][j-1]
; - et la valeur du tableau de départ contenue dans la case
(0\,,j) c’est-à-dire
tab[0][j]
.
Donc si
j
est différent de0
, alors :tab2[0][j] = tab[0][j] + tab2[0][j-1]
. - la somme maximale de la case (0\,,j-1) c’est-à-dire
-
-
Justifier que si
i
etj
sont différents de0
, alors :tab2[i][j] = tab[i][j] + max(tab2[i-1][j], tab2[i][j-1])
.Réponse
tab2[i][j]
désigne la somme maximale d’une case (0\,,j) qui ne se trouve ni dans la première ligne ni dans la première colonne. Pour une telle case, il y a deux façons d’y arriver :- de la gauche par la case (i\,,j-1);
- du haut par la case (i-1\,,j).
Pour calculer
tab2[0][j]
il faut donc :- déterminer des deux cases précédentes celle qui contient la plus
grande somme maximale c’est-à-dire
max(tab2[i-1][j], tab2[i][j-1])
; - ajouter ce maximum à la valeur du tableau de départ contenue dans
la case (i\,,j) c’est-à-dire
tab[i][j]
.
Donc si
i
etj
sont différents de0
, alors :tab2[i][j] = tab[i][j] + max(tab2[i-1][j], tab2[i][j-1])
. -
On veut créer la fonction récursive
somme_max
ayant pour paramètres un tableautab
, un entieri
et un entierj
. Cette fonction renvoie la somme maximale pour tous les chemins possibles allant de la case (0\,,0) à la case (i\,,j) detab
.-
Quel est le cas de base, à savoir le cas qui est traité directement sans faire appel à la fonciton
somme_max
? Que renvoie-t-on dans ce cas ?Réponse
Le cas de base correspond au traitement de la case de départ (0\,,0) c’est à dire pour i = j = 0. Dans ce cas, il n’y a aucun calcul à réaliser. Il suffit de renvoyer la valeur de la case (0\,,0) c’est-à-dire
tab[0][0]
. En effet, le chemin venant de débuter, la somme des valeurs rencontrées se limite simplement à la valeur de la case de départ. -
À l’aide de la question précédente, écrire en Python la fonction récursive
somme_max
.Réponse
Dans les questions précédentes, nous avons vu :
- le cas de base : la case de départ (0\,,0) ;
- le cas d’une case de la première ligne : (0\,,j), j\neq 0.
Il manque le cas d’une case de la première colonne : (i\,,0), i\neq 0.
On suit la même approche qu’à la question 3.b. :
Le schéma permet d’en déduire comment calculer
tab2[i, 0]
:tab2[i, 0] = tab[i, 0] + tab2[i-1, 0]
On peut maintenant écrire la fonction
somme_max
:- Cas de base. Case de départ (0\,,0).
- Case en première ligne (sauf case de départ)
- Case en première colonne (sauf case de départ)
- Case quelconque (sauf premières ligne et colonne)
-
Quel appel de fonction doit-on faire pour résoudre le problème initial ?
Réponse
Remarque La question me semble ambigüe. Doit-on répondre à cette question dans le cas général ou avec l’exemple vu en début d’énoncé ? La deuxième option me semble plus simple.
-
Option 1. Exemple de tableau vu en début dénoncé
On suppose que le tableau
tab
donné en exemple en début d’énoncé a été préalablement déclaré.Pour connaître la somme maximale pour tous les chemins possibles allant de la case (0\,,0) à (2\,,3) dans ce tableau, il faut exécuter l’appel
somme_max(tab, 2, 3)
renvoyant16
. -
Option 2. Cas général
On suppose qu’un tableau
tab
contenantn
lignes etp
colonnes a été préalablemant déclaré.Remarque. À partir de
tab
, on peut obtenirn
etp
de la façon suivante :Pour connaître la somme maximale pour tous les chemins possibles allant de la case (0\,,0) à (n-1\,,p-1) dans ce tableau, il faut exécuter l’appel
somme_max(tab, n-1, p-1)
.
-
-