ajout sequence recursivité

This commit is contained in:
Florian Mathieu
2024-09-02 18:32:04 +02:00
parent f33a3146a0
commit b09487d067
34 changed files with 18135 additions and 0 deletions

View File

@@ -0,0 +1,82 @@
# Diviser pour régner
------
Parfois la résolution d'un problème peut être très longue et répétitive. Il s'agit d'appliquer une méthode encore et encore jusqu'à obtenir une solution.
Par exemple lorsque l'on recherche un élément dans un tableau, on regarde le premier élément, puis le second ainsi de suite...
La méthode diviser pour régner permet de décomposer un problème en sous-problèmes. Une fois les sous-problèmes crées on les résout puis on combine les résultats de ces sous problème pour trouver le résultat final.
Le tout se fait de manière récursive.
Récapitulons :
- Décomposition du problème en sous problèmes
- Résolution des sous problèmes
- Combinaison des résultats
Nous allons ici parler de la recherche dichotomique afin d'illustrer notre propos. Ce n'est pas le meilleur exemple, mais c'est le plus trivial. Nous profiterons de la partie TP pour voir d'autres applications de cette méthode.
## 1. Recherche dichotomique
### 1. 1. Principe
La recherche dichotomique est une recherche d'un élément dans un tableau trié. Il s'agit de la recherche optimale pour ce type de situation.
<u>Recherche dans un tableau :</u>
Tant que l'indice de début est inférieur à l'indice de fin :
- Sélectionner la valeur au milieu du tableau
- Si la valeur du milieu est supérieur à la valeur recherchée
- Rechercher dans la partie gauche du tableau
- Si la valeur du milieu est inférieur à la valeur recherchée
- Rechercher dans la partie droite du tableau
- Sinon
- Renvoyer la valeur recherchée
### 1. 2. Diviser pour régner sur la recherche dichotomique
<u>**Décomposition du problème en sous problèmes :**</u>
Afin d'appliquer la méthode, il faut dans un premier temps diviser le problème en sous problèmes.
C'est pourquoi l'exemple de la recherche dichotomique n'est pas le meilleur, car il décompose le problème en 1 seul sous problème et pas en plusieurs.
Mais peut importe, la décomposition à lieu lorsqu'on recherche soit dans la partie de droite ou de gauche.
<u>**Résolution des sous problèmes :**</u>
La résolution du sous problèmes ici se fait lorsque l'on à 1 seul élément, soit il s'agit de l'élément recherché, soit ça ne l'est pas.
**<u>Combinaison des résultats :</u>**
Une fois le résultat trouvé de ce sous problème, il est renvoyé (ici pas de combinaison, il n'y a qu'un sous problème)
### 1. 3. Code de la fonction
```python
def recherche(t,v,d,f):
"""Fonction récursive de recherche
param t (tableau) : tableau dans lequel on recherche l'élément
param v ( ) : valeur à rechercher
param d (int) : indice de début de recherche dans le tableau
param f (int) : indice de fin de recherche dans le tableau
return (None/ ) : None si pas trouvé, position de v dans t sinon"""
if d > f :
return None
milieu = (d+f)//2
if t[milieu] < v :
return recherche(t,v,milieu+1,f)
elif t[milieu] > v :
return recherche(t,v,d,milieu-1)
else :
return milieu
def recherche_dichotomique(t,v):
"""Algo de recherche dichotomique, renvoie None si pas trouvé, position de v dans t sinon,
le tableau t est trié, v est la valeur à rechercher dans le tableau"""
return recherche(t,v,0,len(t)-1)
```

View File

@@ -0,0 +1,21 @@
def recherche(t,v,d,f):
"""Fonction récursive de recherche
param t (tableau) : tableau dans lequel on recherche l'élément
param v ( ) : valeur à rechercher
param d (int) : indice de début de recherche dans le tableau
param f (int) : indice de fin de recherche dans le tableau
return (None/ ) : None si pas trouvé, position de v dans t sinon"""
if d > f :
return None
milieu = (d+f)//2
if t[milieu] < v :
return recherche(t,v,milieu+1,f)
elif t[milieu] > v :
return recherche(t,v,d,milieu-1)
else :
return milieu
def recherche_dichotomique(t,v):
"""Algo de recherche dichotomique, renvoie None si pas trouvé, position de v dans t sinon,
le tableau t est trié, v est la valeur à rechercher dans le tableau"""
return recherche(t,v,0,len(t)-1)

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

View File

@@ -0,0 +1,57 @@
# TP Diviser pour régner
------
## Tri fusion
### 1. 1. Première approche
Une fonction de tri s'applique à un tableau, ce tableau contient des éléments comparables entre eux. Le but est donc de les ranger par ordre croissant. Nous connaissons déjà le tri par insertion et le tri par sélection. Cependant en utilisant le principe de "diviser pour régner" il est possible de concevoir un tri plus efficace. Il est appelé "tri fusion".
Le tri fusion se décompose comme suit :
Le tri sépare le tableau en 2 moitiés égale (à un élément près pour les longueurs impaire) puis on trie avec le tri fusion et cela de manière récursive. Puis on trie les éléments des deux tableau triés, c'est la fusion.
1. Lorsque l'on découpe le tableau en deux parties, comment garantir que l'on arrivera à un tableau trié ?
2. Une fois ces tableaux triés obtenus, expliquer comment pouvons nous faire pour assembler ces tableaux et obtenir un nouveau tableau trié. (sans faire de code)
```
Par exemple :
Si l'on a [2,6,78] et [4,5,98] le résultat doit être [2,4,5,6,78,98]
```
3. Dessiner l'arbre de décomposition et de fusion du tableau [7,89,15,2,65,10,8,11,1]
### 1. 2. Implémentation
L'algorithme est composé de deux fonction :
- une fonction nommée *fusion( )* prenant en paramètre deux tableau trié et faisant la fusion des deux.
- une fonction nommée *tri_fusion( )* prenant en paramètre un tableau et le décompose en deux tableaux auxquels on appliquera tri_fusion
- Les deux tableaux sont ensuites fusionnés grâce à *fusion( )*
1. Ecrire dans un premier temps la fonction *fusion( )* prenant en paramètre deux tableaux triés et effectuant la fusion des deux tableaux.
```python
>>> fusion([2,6,78],[4,5,98])
[2,4,5,6,78,98]
```
> Cette fonction ne doit pas être récursive. (=> Boucles)
2. Ecrire la fonction *tri_fusion( )* prenant en paramètre un tableau et effectue le tri fusion. La valeur renvoyée est le tableau trié
- Decomposition en 2 tableaux
- Tri fusion sur ces deux tableaux
- Fusion des deux tableaux triés
### 1. 3. Complexité
La complexité du tri fusion est intereséssante à étudier.
1. Pour cela, récuperez le fichier nommé *complexité.py*
2. Expliquez les lignes 25 à 54
3. Exécutez le code
1. Expliquez à quoi correspondent les courbes (c'est normal si elles ne sont pas lisses)
2. Bonus : Pourquoi les courbes ne sont pas lisses ?
4. Le tri fusion est-il plus efficace que les autres tris ?

View File

@@ -0,0 +1,65 @@
# TP Diviser pour régner correction
------
## 1. Tri fusion
### 1. 1. Première approche
1. Lorsque l'on découpe le tableau en deux parties, comment garantir que l'on arrivera à un tableau trié ?
> On obtiendra des tableaux triés lorsque la longueur sera égale à 1
2. Une fois ces tableaux triés obtenus, expliquer comment pouvons nous faire pour assembler ces tableaux et obtenir un nouveau tableau trié. (sans faire de code)
```
Par exemple :
Si l'on a [2,6,78] et [4,5,98] le résultat doit être [2,4,5,6,78,98]
```
> Lorsqu'on à deux tableau, il faut ajouter les éléments un à un dans un nouveau tableau en prenant l'élément le plus petit.
> []
> [2]
>
> [2,4]
>
> [2,4,5]
>
> [2,4,5,6]
>
> ...
>
> [2,4,5,6,78,98]
3. Dessiner l'arbre de décomposition et de fusion du tableau [7,89,15,2,65,10,8,11,1]
![image-20220804131314159](../Images/image-20220804131216082.png)
### 1. 2. Implémentation
Voir fichier python tri_fusion.py
### 1. 3. Complexité
1. Pour cela, récuperez le fichier nommé *complexité.py*
2. Expliquez les lignes 25 à 54
> Exemple de construction des resultats pour tri_fusion
> utilisation module time
3. Exécutez le code
1. Expliquez à quoi correspondent les courbes (c'est normal si elles ne sont pas lisses)
> Moyenne de temps d'exec de chaque tri en fonction de la taille du tableau
1. Bonus : Pourquoi les courbes ne sont pas lisses ?
> Car le pc effectue d'autre tâche à côté et cela influence le temps d'éxécution
4. Le tri fusion est-il plus efficace que les autres tris ?
> Oui complexité n (log2 n)

View File

@@ -0,0 +1,54 @@
import matplotlib.pyplot as pylab
import time
import random
def construit_tab_alea(taille) :
"""
Fonction qui crée un tableau avec des valeur aléatoire de taille taille
param taille : (int) Taille du tableau
return : (list) Tableau à renvoyer
"""
tab = []
for i in range(taille) :
val = random.randint(0,1000)
tab.append(val)
return tab
def moyenne(tab):
moy = 0
for i in tab :
moy += i
return moy/len(tab)
##############################################################################################################################
"""
# Construction de t_temps_tri_fusion :
t_temps_tri_fusion = []
for taille in t_taille:
t_moy = []
for _ in range(3000):
tab = construit_tab_alea(taille)
t1 = time.process_time()
tri_fusion(tab)
t2 = time.process_time()
duree = t2 - t1
t_moy.append(duree)
duree_moy = moyenne(t_moy)
t_temps_tri_fusion.append(duree_moy)
print("Tri fusion fini")
"""
t_taille = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
# Courbes moyenne :
t_temps_tri_insertion_pire_cas_moy = [0.0, 0.0, 5.208333333333333e-06, 0.0, 5.208333333333333e-06, 5.208333333333333e-06, 1.0416666666666666e-05, 5.208333333333333e-06, 1.5625e-05, 5.208333333333333e-06, 1.5625e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 2.604166666666667e-05, 3.125e-05, 3.125e-05, 4.1666666666666665e-05, 4.1666666666666665e-05, 4.6875e-05, 5.208333333333334e-05, 5.208333333333334e-05, 6.25e-05, 6.25e-05, 7.291666666666667e-05, 6.770833333333333e-05, 8.333333333333333e-05, 8.333333333333333e-05, 9.895833333333333e-05, 9.895833333333333e-05, 0.000109375, 0.000109375, 0.00011979166666666666, 0.00013020833333333333, 0.00013020833333333333, 0.00015104166666666667, 0.00015104166666666667, 0.00016666666666666666, 0.00018229166666666667, 0.00017708333333333335, 0.00018229166666666667, 0.000203125, 0.000203125, 0.00022395833333333333, 0.00022395833333333333, 0.00023958333333333332, 0.00025, 0.00026041666666666666, 0.00026041666666666666, 0.00028125, 0.000296875, 0.00030208333333333335, 0.00032291666666666666, 0.000328125, 0.0003385416666666667, 0.0003541666666666667, 0.0003541666666666667, 0.0003802083333333333, 0.0003958333333333333, 0.000421875, 0.00041145833333333334, 0.0004427083333333333, 0.00044791666666666667, 0.0004583333333333333, 0.000515625, 0.000515625, 0.0005364583333333333, 0.0005364583333333333, 0.0005520833333333334, 0.0005572916666666667, 0.0005833333333333334, 0.00059375, 0.000609375, 0.0006145833333333333, 0.0006302083333333333, 0.0006458333333333333, 0.0006666666666666666, 0.0006822916666666667, 0.000703125, 0.0007239583333333333, 0.0007395833333333333, 0.0007552083333333333, 0.0007864583333333333, 0.0007864583333333333, 0.0008177083333333334, 0.000828125, 0.0008541666666666667, 0.0008697916666666667, 0.0008958333333333333, 0.00090625, 0.0009427083333333334, 0.0009635416666666667, 0.0009791666666666666, 0.0009947916666666666, 0.0010208333333333332, 0.0010260416666666666, 0.0010572916666666667, 0.001078125, 0.00109375, 0.001109375]
t_temps_tri_insertion_meilleur_cas_moy = [0.0, 5.208333333333333e-06, 0.0, 0.0, 5.208333333333333e-06, 0.0, 5.208333333333333e-06, 5.208333333333333e-06, 5.208333333333333e-06, 5.208333333333333e-06, 0.0, 5.208333333333333e-06, 1.0416666666666666e-05, 0.0, 5.208333333333333e-06, 5.208333333333333e-06, 5.208333333333333e-06, 5.208333333333333e-06, 1.0416666666666666e-05, 5.208333333333333e-06, 1.0416666666666666e-05, 5.208333333333333e-06, 1.0416666666666666e-05, 1.0416666666666666e-05, 5.208333333333333e-06, 1.0416666666666666e-05, 1.0416666666666666e-05, 5.208333333333333e-06, 1.0416666666666666e-05, 1.0416666666666666e-05, 1.0416666666666666e-05, 1.0416666666666666e-05, 1.0416666666666666e-05, 5.208333333333333e-06, 1.5625e-05, 1.0416666666666666e-05, 1.0416666666666666e-05, 1.5625e-05, 1.0416666666666666e-05, 5.208333333333333e-06, 1.5625e-05, 1.0416666666666666e-05, 1.5625e-05, 1.0416666666666666e-05, 1.5625e-05, 1.5625e-05, 1.5625e-05, 1.0416666666666666e-05, 1.5625e-05, 1.5625e-05, 1.5625e-05, 1.5625e-05, 1.5625e-05, 1.0416666666666666e-05, 1.0416666666666666e-05, 1.5625e-05, 2.0833333333333333e-05, 1.5625e-05, 1.5625e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 1.5625e-05, 1.5625e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 1.5625e-05, 2.0833333333333333e-05, 1.5625e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 1.5625e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 2.604166666666667e-05, 2.0833333333333333e-05, 2.604166666666667e-05, 2.604166666666667e-05, 2.604166666666667e-05, 2.0833333333333333e-05, 2.604166666666667e-05, 2.604166666666667e-05, 2.604166666666667e-05, 2.604166666666667e-05, 2.604166666666667e-05, 2.0833333333333333e-05, 2.0833333333333333e-05, 2.604166666666667e-05, 2.604166666666667e-05, 2.604166666666667e-05, 2.0833333333333333e-05, 2.604166666666667e-05, 3.125e-05, 2.604166666666667e-05, 3.125e-05, 2.604166666666667e-05]
t_temps_tri_fusion = [0.0, 0.0, 5.208333333333333e-06, 0.0, 1.0416666666666666e-05, 1.5625e-05, 5.208333333333333e-06, 2.604166666666667e-05, 5.208333333333333e-06, 2.604166666666667e-05, 2.0833333333333333e-05, 1.0416666666666666e-05, 2.604166666666667e-05, 4.6875e-05, 3.6458333333333336e-05, 5.7291666666666666e-05, 5.7291666666666666e-05, 4.1666666666666665e-05, 4.6875e-05, 6.25e-05, 7.291666666666667e-05, 7.8125e-05, 6.770833333333333e-05, 7.291666666666667e-05, 6.25e-05, 9.375e-05, 8.854166666666667e-05, 0.00011979166666666666, 0.00013020833333333333, 8.854166666666667e-05, 8.854166666666667e-05, 0.000109375, 8.854166666666667e-05, 0.00011458333333333333, 0.00013020833333333333, 0.00013020833333333333, 0.00013020833333333333, 0.00011979166666666666, 0.00015104166666666667, 0.000140625, 0.00011979166666666666, 0.00017708333333333335, 0.00016145833333333333, 0.00013541666666666666, 0.0001875, 0.00019791666666666666, 0.00017708333333333335, 0.00016666666666666666, 0.00019270833333333333, 0.00016666666666666666, 0.00023958333333333332, 0.000203125, 0.00021354166666666668, 0.00021354166666666668, 0.000234375, 0.00022395833333333333, 0.00022395833333333333, 0.000234375, 0.00023958333333333332, 0.00026041666666666666, 0.00023958333333333332, 0.0003125, 0.000328125, 0.00030729166666666665, 0.000328125, 0.00030208333333333335, 0.00028125, 0.00028645833333333333, 0.00030729166666666665, 0.00030729166666666665, 0.0002916666666666667, 0.000328125, 0.00030208333333333335, 0.00030729166666666665, 0.00034375, 0.0003177083333333333, 0.00032291666666666666, 0.0003333333333333333, 0.00030208333333333335, 0.00032291666666666666, 0.00034895833333333334, 0.0003541666666666667, 0.0003958333333333333, 0.000390625, 0.0004166666666666667, 0.00040625, 0.000359375, 0.0004010416666666667, 0.000375, 0.000390625, 0.000390625, 0.00036979166666666665, 0.00044791666666666667, 0.00044791666666666667, 0.00040625, 0.0004427083333333333, 0.00040625, 0.0003958333333333333, 0.0004635416666666667, 0.000421875]
t_temps_selection_moy = [0.0, 5.208333333333333e-06, 5.208333333333333e-06, 1.0416666666666666e-05, 5.208333333333333e-06, 1.0416666666666666e-05, 2.0833333333333333e-05, 1.5625e-05, 2.0833333333333333e-05, 2.604166666666667e-05, 3.125e-05, 3.125e-05, 3.6458333333333336e-05, 3.6458333333333336e-05, 3.6458333333333336e-05, 4.6875e-05, 4.1666666666666665e-05, 4.6875e-05, 5.208333333333334e-05, 5.7291666666666666e-05, 5.7291666666666666e-05, 6.25e-05, 6.25e-05, 7.291666666666667e-05, 7.8125e-05, 7.8125e-05, 8.854166666666667e-05, 9.375e-05, 9.895833333333333e-05, 0.00010416666666666667, 0.00010416666666666667, 0.000109375, 0.00011979166666666666, 0.00011979166666666666, 0.000125, 0.000125, 0.000140625, 0.00013541666666666666, 0.00015104166666666667, 0.00015104166666666667, 0.00016666666666666666, 0.00016666666666666666, 0.000171875, 0.00017708333333333335, 0.00018229166666666667, 0.00019270833333333333, 0.000203125, 0.000203125, 0.00020833333333333335, 0.00022395833333333333, 0.00022395833333333333, 0.000234375, 0.000234375, 0.00023958333333333332, 0.0002552083333333333, 0.00026041666666666666, 0.000265625, 0.0002708333333333333, 0.00028645833333333333, 0.00028645833333333333, 0.00030208333333333335, 0.00030208333333333335, 0.0003125, 0.0003177083333333333, 0.000328125, 0.0003385416666666667, 0.00034375, 0.000359375, 0.000359375, 0.00036979166666666665, 0.0003802083333333333, 0.00038541666666666667, 0.0003958333333333333, 0.00040625, 0.000421875, 0.00043229166666666665, 0.00043229166666666665, 0.000453125, 0.000453125, 0.0004635416666666667, 0.00046875, 0.00047395833333333334, 0.0005, 0.0005104166666666666, 0.0005260416666666666, 0.00053125, 0.0005416666666666666, 0.0005416666666666666, 0.0005520833333333334, 0.0005625, 0.000578125, 0.0005885416666666667, 0.0005989583333333333, 0.0006145833333333333, 0.0006197916666666667, 0.000640625, 0.000640625, 0.0006614583333333333, 0.0006875, 0.0006927083333333334]
pylab.plot(t_taille,t_temps_tri_insertion_pire_cas_moy,label = 'tri insertion pire cas')
pylab.plot(t_taille,t_temps_tri_insertion_meilleur_cas_moy,label = 'tri insertion meilleur cas')
pylab.plot(t_taille,t_temps_selection_moy,label = 'tri selection')
pylab.plot(t_taille,t_temps_tri_fusion,label = 'tri fusion')
pylab.legend()
pylab.show()

View File

@@ -0,0 +1,42 @@
def fusion(t1,t2):
"""Fusionne deux tableau trié en un seul.
param t1 (tab) : premier tableau trié
param t2 (tab) : second tableau trié
return (tab) : fusion des deux tableaux"""
global compteur
tab_final = []
ind1 = 0
ind2 = 0
while ind1<len(t1) and ind2<len(t2):
if t1[ind1] < t2[ind2] :
tab_final.append(t1[ind1])
ind1+=1
else:
tab_final.append(t2[ind2])
ind2+=1
while ind1<len(t1) :
tab_final.append(t1[ind1])
ind1+=1
while ind2<len(t2) :
tab_final.append(t2[ind2])
ind2+=1
return tab_final
def tri_fusion(t):
long = len(t)
if long <= 1 :
return t
else :
t1 = []
t2 = []
i = 0
moitie = long//2
while i < moitie :
t1.append(t[i])
t2.append(t[i+moitie])
i+=1
if (i+moitie)<(long):
t2.append(t[i+moitie])
t1 = tri_fusion(t1)
t2 = tri_fusion(t2)
return fusion(t1,t2)

147
Recursivité/README.md Normal file
View File

@@ -0,0 +1,147 @@
## Recursivité
> La récursivité est un style de programmation permettant de simplifier l'écriture de nombreux problèmes.
### Un peu de culture
La récursivité, en informatique, est une pratique qui permet à une fonction de s'appeler elle-même.
On peut comparer cela à la [mise en abyme](https://fr.wikipedia.org/wiki/Mise_en_abyme), procédé littéraire qui décrit une oeuvre incrustée dans elle même@@@@@@@@@@@@@@@@
**La fonction récursive s'appelle elle même dans sa définition.**
-------------------------------
### Mauvais exemple
Rien de tel qu'un mauvais usage pour mieux comprendre un concept.
Voici une fonction récursive :
```python
def fct_recursive() :
print("Je fais un appel de la fonction")
fct_recursive()
```
Cette fonction s'appelle elle même, mais elle présente un problème.
Si nous l'appelons, le résultat sera celui-ci :
```python
>>> fct_recursive()
"Je fais un appel de la fonction"
"Je fais un appel de la fonction"
"Je fais un appel de la fonction"
"Je fais un appel de la fonction"
"Je fais un appel de la fonction"
"Je fais un appel de la fonction"
"Je fais un appel de la fonction"
...
```
Tout comme les boucles, il faut créer une instruction permettant d'arrêter l'exécution du code, en récursif nous l'appelons **le cas d'arrêt**. Il permettra d'éviter les appels **infinis**
### Le cas d'arrêt
Afin de stopper l'exécution du code il est donc essentiel de créer une instruction n'appelant pas notre fonction.
Par exemple :
Voici la fonction somme(n) se définissant comme :
$`somme(n) = \left\{ \begin{array}{ll} 0 {~si~} n = 0\\ n + somme(n -1){~sinon.} \end{array}\right.`$
```python
def somme(n) :
if n == 0 :
return 0
else :
return n + somme(n-1)
```
Cette fonction s'appelle donc elle même jusqu'à avoir n égal à 0.
Mais quel sera le résultat de *somme(3)* ?
Pour obtenir cette réponse nous allons dérouler *à la main* le code :
```
somme(3) = 3 + somme(2)
somme(2) = 2 + somme(1)
somme(1) = 1 + somme(0)
somme(0) = 0
```
Voici les différents appels de fonctions pour somme(3). Mais là, le résultat n'est pas encore obtenu.
Pour cela il faut pour cela reprendre les appels de fonctions pour revenir jusqu'à somme(3)
```
somme(0) = 0
somme(1) = 1 + 0 = 1
somme(2) = 2 + 1 = 3
somme(3) = 3 + 3 = 6
```
Ici nous observons donc 4 appels de fonctions pour résoudre somme(3).
-----------
### Appel de fonction en python
En python il existe une limite au nombre d'appel de fonction que l'on peut faire pour une fonction récursive.
En effet, avec notre exemple nous voyons que pour obtenir somme(3) nous faisons 4 appels de fonction.
Ces appels de fonction **s'empilent** en espace mémoire, python peut stocker autour de 1000 appels.
Si cette limite est dépassée alors l'erreur **RecursionError** apparaîtra.
```python
>>> somme(1001)
...
RecursionError: maximum recursion depth exceeded in comparison
```
### Autre type de récursivité
Il existe divers types de récursivité :
- La récursivité multiple
- La récursivité double
- La récursivité imbriquée
- etc ...
Ces différents types de récursivité sont quelques peu différents de ce que l'on vient de voir. Mais nous pourrions les rencontrer dans la suite du programme.
### Récursivité double
En effet à la différence de la récursivité dite **simple** il y aura ici plusieurs appels de fonctions dans une même instruction.
> En mathématiques, la suite de Fibonacci est une suite de nombres entiers dont chaque terme successif représente la somme des deux termes précédents, et qui commence par 0 puis 1. Ainsi, les dix premiers termes qui la composent sont 0, 1, 1, 2, 3, 5, 8, 13, 21 et 34.
```python
def fibonacci(n):
if n == 0 :
return 0
elif n == 1 :
return 1
else :
return fibonnaci(n-1) + fibonnaci(n-2)
```
-----------------
Auteurs : Florian Mathieu, Timothée Decoster, Enzo Frémeaux
Licence CC BY NC
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas dUtilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.

View File

@@ -0,0 +1,78 @@
# TD Récursivité :
------
## 1. Application du cours
### 1. 1. Fonction somme :
1) Combien d'appel de fonction sont nécessaire pour somme(5) ? somme(n) ?
### 1. 2. Fonction factorielle :
1. Ecrire le code de la fonction *factorielle*(n) étant défini comme :
$$
\text{factorielle}(n) =
\begin{cases}
1 & \text{si } n = 0 \\
n \times \text{factorielle}(n - 1) & \text{sinon.}
\end{cases}
$$
2) Quels seront les appels effectués pour obtenir factorielle(4) ?
## 2. TD
### 2. 1. Fonction mystère :
1. Que fait la fonction mystère ci-dessous :
```python
def mystere(i,k):
if i<=k :
print(i)
mystère(i+1,k)
```
### 2. 2. Nombre de chiffre d'un nombre :
Ecrire une fonction nb_chiffre(n) permettant d'obtenir le nombre de chiffre d'un nombre :
```python
>>> nb_chiffre(9)
1
>>> nb_chiffre(99)
2
```
### 2. 3. Maximum d'un tableau :
Ecrire une fonction maximum(t) permettant d'obtenir le nombre le plus grand d'un tableau :
> Tips :
>
> - Utilisez la fonction max(a,b)
> - Les slices
> - t = [0,1,2]
> - t[2:] => [2]
## 3. Bonus :
### 3. 1. Suite de Syracuse :
La suite de syracuse est une suite définie comme :
$$
U_{n+1} =
\begin{cases}
U_n / 2 & \text{si } U_n \text{ est pair} \\
3U_n + 1 & \text{sinon}
\end{cases}
$$
Sachant que U<sub>0</sub> est supérieur à 1
1. Ecrire la fonction *syracuse(u)* affichant les valeurs de la suite de syracuse.
La suite s'arrête lorsque *u* est inférieur ou égal à 1

Binary file not shown.

View File

@@ -0,0 +1,71 @@
# TD Récursivité :
------
## 1. Application du cours
### 1. 1. Fonction somme :
Combien d'appel de fonction sont nécessaire pour somme(0), somme(5) et somme(n) ?
> Il faut 1 appels pour somme(0), 6 pour somme(5), n+1 pour somme(n)
### 1. 2. Fonction factorielle :
1)
```python
def factorielle(n) :
if n == 0 :
return 1
else :
return n * factorielle(n-1)
```
2)
> Il y aura factorielle(4), factorielle(3), factorielle(2), factorielle(1), factorielle(0)
### 2. 1. Fonction mystère :
1. Que fait la fonction mystère ci-dessous :
> La fonction mystère affiche les entiers entre i et k
### 2. 2. Nombre de chiffre d'un nombre :
Ecrire une fonction nb_chiffre(n) permettant d'obtenir le nombre de chiffre d'un nombre :
```python
def nb_chiffre(n) :
if n <= 9 :
return 1
else :
return 1 + nb_chiffre(n//10)
```
### 2. 3. Maximum d'un tableau :
```python
def maximum(t):
if len(t) == 0:
return -1
elif len(t) == 1 :
return t[0]
else :
return max(t[0], maximum(t[1:]))
```
## 3. Bonus :
### 3. 1. Suite de Syracuse :
```python
def syracuse(u):
print(u)
if u > 1 :
if u%2 == 0 :
return syracuse(u//2)
else :
return syracuse(u*3 + 1)
```

View File

@@ -0,0 +1,36 @@
def fct_recursive() :
print("Je suis un appel de la fonction")
fct_recursive()
def somme(n) :
if n == 0 :
return 0
else :
return n + somme(n-1)
def factorielle(n) :
if n == 0 :
return 1
else :
return n * factorielle(n-1)
def mystere(i,k):
if i<=k :
print(i)
boucle(i+1,k)
def maximum(t):
if len(t) == 0:
return -1
elif len(t) == 1 :
return t[0]
else :
return max(t[0], maximum(t[1:]))
def syracuse(u):
print(u)
if u > 1 :
if u%2 == 0 :
return syracuse(u//2)
else :
return syracuse(u*3 + 1)

View File

@@ -0,0 +1,24 @@
def recherche_dichotomique(t, v):
debut = 0
fin = len(t)-1
while debut <= fin :
milieu = (debut + fin) // 2
print(milieu,debut,fin)
if t[milieu] == v :
return True
else:
if t[milieu] > v :
fin = milieu - 1
else :
debut = milieu + 1
return False
def recherche_recur(t,v):
if len(t) == 1:
return t[0] == v
else :
milieu = len(t)//2
if t[milieu] > v :
return recherche_recur(t[:milieu],v)
else :
return recherche_recur(t[milieu:],v)

29
Recursivité/TP/TP.md Normal file
View File

@@ -0,0 +1,29 @@
## Activité : La récursivité dans les jeux vidéo
### Contexte :
Imaginez un jeu vidéo populaire où le héros doit traverser différents niveaux pour sauver un personnage captif. Chaque niveau est plus difficile que le précédent, et chaque niveau contient des mini-boss qu'il faut vaincre avant de passer au suivant.
### Objectif de l'activité :
Utiliser la récursivité pour simuler le parcours du héros à travers les niveaux du jeu.
### Instructions :
### Présentation du problème :
- Le héros commence au niveau 1 et doit atteindre le niveau `n`.
- À chaque niveau, il y a un certain nombre de mini-boss à vaincre avant de passer au niveau suivant.
- Si le héros vainc tous les mini-boss d'un niveau, il passe au niveau suivant, sinon il recommence le même niveau.
### Modélisation en pseudo-code :
Écrire une fonction récursive `traverse_levels` qui prend en entrée le niveau actuel et le nombre total de niveaux.
- Si le niveau actuel est supérieur au nombre total de niveaux, le héros a gagné.
- Sinon, le héros combat les mini-boss et passe au niveau suivant.
### 3. Exemple de code en Python
```python
def combat_mini_bosses(level):
pass
def traverse_levels(current_level, total_levels):
pass
```

View File

@@ -0,0 +1,69 @@
# TP Récursivité :
------
## 1. Courbe de Koch :
> Prérequis : Module turtle
La courbe de koch est une figure récursive pouvant ressembler à cela :
> Inserer un exemple
Celle-ci possède un cas de base d'ordre 0, il est représenté par un segment. Le cas d'ordre 1 est ce même segment découpé en 3, la partie du milieu est quand à elle un triangle équilatéral sans sa base (ou un chapeau ^).
> Insérer les image ordre 0 et 1
Le cas d'ordre 2 reprend le cas d'ordre 1 est pour chaque segment, le redécoupe et dessine ce "triangle".
Le cas d'ordre n reprend le cas d'ordre n-1 puis refait la même chose... Ainsi de suite
1. Ecrire de manière récursive le code de la fonction courbe_koch(n, cote) permettant de dessiner cette courbe.
Nous voulons obtenir maintenant un flocon de koch. Celui-ci répète plusieurs fois la courbe de koch afin de revenir à son point initial.
2. Ecrire le code de la fonction flocon() qui dessine le flocon de la courbe de koch
> inserer flocon courbe koch
## 2. Triangle de Pascal :
Le triangle de pascal représente les coefficients binomiaux sous la forme d'un triangle :
coef(n,p) : *fonction permettant de calculer les coefficients*
coef(n,p) :
- 1 **si p = 0 ou n == p**
- coef(n-1,p-1) + coef(n-1,p) **sinon**
1. Ecrire le code de la fonction coef(n,p)
Le sommet du triangle est le résultat de coef(0,0), la première ligne elle est représenté par coef(1,0) et coef(1,1), ainsi de suite pour les autres lignes
2. A l'aide de deux boucles écrire un code permettant d'afficher les 6 premières lignes du triangle.
## 3. Recherche dichotomique :
La recherche dichotomique fonctionne sur un tableau trié, et permet en fonction de la longueur du tableau n de trouver un élément de façon optimale.
Voici le code de la recherche dichotomique (programme 1ère) de manière itérative :
```python
def recherche_dichotomique(t, v):
debut = 0
fin = len(t)-1
while debut <= fin :
milieu = (debut + fin) // 2
print(milieu,debut,fin)
if t[milieu] == v :
return True
else:
if t[milieu] > v :
fin = milieu - 1
else :
debut = milieu + 1
return False
```
1. Ecrire ce code en récursif

View File

@@ -0,0 +1,27 @@
import turtle
def courbe_koch(n, l):
if n == 0 :
turtle.forward(l)
else :
courbe_koch(n-1, l/3)
turtle.left(60)
courbe_koch(n-1, l/3)
turtle.left(-120)
courbe_koch(n-1, l/3)
turtle.left(60)
courbe_koch(n-1, l/3)
def flocon(n,l,i=3):
if i != 0:
courbe_koch(n,l)
turtle.left(-120)
flocon(n,l,i-1)
turtle.setheading(0) # orientation intiale de la tête : vers la droite de l'écran
turtle.hideturtle() # on cache la tortue
turtle.speed(0) # on accélère la tortue
turtle.color('green')
#flocon(1,300)
#courbe_koch(,400)
print(8)

View File

@@ -0,0 +1,10 @@
def coef(n,p):
if p==0 or n == p :
return 1
else :
return coef(n-1,p-1) + coef(n-1,p)
for i in range(19):
for j in range(i+1):
print(coef(i,j),' ',end='')
print()

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 MiB

BIN
Recursivité/fibonacci.pdf Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,375 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Exercices sur la récursivité et la programmation dynamique\n",
"\n",
"## Évolution des abonnements\n",
"\n",
"Un youtuber constate chaque mois qu'il recrute 3000 nouveaux abonnés mais dans le même temps la lassitude pousse 2% de ses fidèles à se désabonner. Ce mois-ci (n=0) il compte 100000 abonnés et il souhaite pouvoir calculer les prédictions de ses abonnés pour démarcher des sponsors dans les mois à venir. Écrivez récursivement la fonction `prev_abo` qui calcule le nombre d'abonné au mois n.\n",
"\n",
"Utilisez votre fonction `prev_abo` pour calculer le nombre d'abonnés dans les mois à venir.\n",
"\n",
"D'après vous, le youtuber peut-il prétendre à ces sponsors qu'il va bientôt atteindre les 200000 abonnés ? Utilisez votre programme pour constater l'évolution des abonnés à long terme."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Sans maitrise la puissance n'est rien\n",
"\n",
"Écrivez par récurence une function `puissance(x: float, n: int) -> float` qui calcule $x^n$ pour n >= 0 en utilisant uniquement des multiplications et la valeur de $x^0$."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def puissance(x:float, n:int) -> float:\n",
" \"\"\" n must be >= 0\n",
" >>> puissance(0,0)\n",
" 1\n",
" >>> puissance(1,0)\n",
" 1\n",
" >>> puissance(1,1)\n",
" 1\n",
" >>> puissance(1,3)\n",
" 1\n",
" >>> puissance(2,3)\n",
" 8\n",
" >>> puissance(10,5)\n",
" 100000\n",
" \"\"\"\n",
"\n",
"import doctest\n",
"doctest.testmod(optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE, verbose = False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Un PGCD pour l'examen ?\n",
"\n",
"Écrivez une fonction `pgcd` qui calcule le PGCD entre 2 nombres entiers avec l'algorithme d'Euclide qui dit ceci :\n",
"- Le pgcd de a (a > 0) et b est le même que le pgcd de b et c avec c qui est le reste de la division entière (en python le modulo :**%**) de a par b. \n",
"- Le pgcd de a par 0 est a"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Réduction de fraction\n",
"\n",
"Utiliser le pgcd précédent pour écrire une fonction `reduc` qui réduit les fractions entières comme ceci : `reduc(12,8)` retourne `(3,2)` car $\\dfrac{12}{8} = \\dfrac{3}{2}$."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Suite de Syracuse\n",
"\n",
"Programmez par **récursivité** la fonction `syracuse(u0: int, n: int)` qui calcule la [suite de Syracuse](https://fr.wikipedia.org/wiki/Conjecture_de_Syracuse#Suite_de_Syracuse) définie **pour des entiers** comme ceci :\n",
"\n",
"$u_o = N$ avec N entier > 0\n",
"\n",
"$u_{n+1}={\\begin{cases}{\\dfrac {u_{n}}{2}} \\; {\\mbox{si }}u_{n}{\\mbox{ est pair,}}\\\\3u_{n}+1 \\; {\\mbox{si }}u_{n}{\\mbox{ est impair.}}\\end{cases}}$\n",
"\n",
"💡 **Si vous appelez récursivement plusieurs fois la fonction avec les mêmes paramètres, il vaut mieux faire 1 seul appel et mettre le résultat dans une variable. Vous limiterez ainsi considérablement le nombre d'appels.**"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def syracuse(u0: int, n: int) -> int:\n",
" \"\"\" Return Syracuse suite value\n",
" u0 must be > 0 ; n must be >= 0\n",
" >>> syracuse(1, 0)\n",
" 1\n",
" >>> syracuse(15, 7)\n",
" 160\n",
" >>> syracuse(15, 4)\n",
" 35\n",
" >>> syracuse(15, 17)\n",
" 1\n",
" \"\"\"\n",
"\n",
"import doctest\n",
"doctest.testmod(optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE, verbose = False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Pour l'appel de la fonction `syracuse(15, 3)` comptez au brouillon combien de fois la fonction `syracuse` se lance en écrivant l'arbre des appels.\n",
"\n",
"Vérifiez cela en modifiant votre programme, puis trouvez le nombre d'appel pour calculer `syracuse(15, 5)`, `syracuse(15, 10)`, `syracuse(15, 15)` et `syracuse(15, 20)`. Que pensez vous de ces derniers résultats ?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Une **conjecture encore non démontrée** en mathématique affirme que pour **tout N entier > 0 il existe toujours un terme de la suite pour lequel $u_n = 1$**.\n",
"\n",
"Écrivez un programme qui montre cette conjecture pour les valeurs de N allant jusqu'à 30."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A ce stade, suivant le code de votre fonction `syracuse`, tout se passe bien (**1 seul appel récursif par fonction**), ou vous avez dû interrompre le programme car sa **compléxité** est telle qu'il ne peut pas répondre dans un temps raisonnable (**3 appels récursifs par fonction**) !\n",
"\n",
"Écrivez maintenant votre programme de recherche du rang pour lequel $u_n=1$ pour un N donné en utilisant un algorithme **itératif (avec une boucle)**. Testez votre code en trouvant les rangs recherchés pour N jusqu'à 100."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Recherche dichotomique récursive !\n",
"\n",
"Écrivez maintenant une fonction `find_dicho_recur` de recherche dichotomique dans une liste triée qui répond `True` ou `False` en fonction du résultat de la recherche. Vous pouvez utiliser les **slices** pour accéder à une sous-liste.\n",
"\n",
"💡 La technique qui consiste à résoudre un problème en résolvant plusieurs parties plus petite du problème s'appelle : **diviser pour régner**."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def find_dicho_recur(liste: list, value: int) -> bool:\n",
" \"\"\" liste must be sorted\n",
" >>> find_dicho_recur([], 0)\n",
" False\n",
" >>> find_dicho_recur([1], 0)\n",
" False\n",
" >>> find_dicho_recur([1], 1)\n",
" True\n",
" >>> find_dicho_recur([1, 2], 1)\n",
" True\n",
" >>> find_dicho_recur([1, 2], 2)\n",
" True\n",
" >>> find_dicho_recur([1, 2], 3)\n",
" False\n",
" >>> find_dicho_recur([1, 2], -1)\n",
" False\n",
" >>> find_dicho_recur([1,2,3], 0)\n",
" False\n",
" >>> find_dicho_recur([1,2,3], 5)\n",
" False\n",
" >>> find_dicho_recur([1,2,3], 1)\n",
" True\n",
" >>> find_dicho_recur([1,2,3], 2)\n",
" True\n",
" >>> find_dicho_recur([1,2,3], 3)\n",
" True\n",
" >>> find_dicho_recur([1,2,3,4], 1)\n",
" True\n",
" >>> find_dicho_recur([1,2,3,4], 2)\n",
" True\n",
" >>> find_dicho_recur([1,2,3,4], 3)\n",
" True\n",
" >>> find_dicho_recur([1,2,3,4], 4)\n",
" True\n",
" >>> find_dicho_recur([1,2,3,4], -1)\n",
" False\n",
" >>> find_dicho_recur([1,2,3,4], 10)\n",
" False\n",
" \"\"\"\n",
"\n",
"import doctest\n",
"doctest.testmod(optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE, verbose = False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Rendu de monnaie optimal !\n",
"\n",
"Nous avons programmé le [rendu de monnaie](https://fr.wikipedia.org/wiki/Probl%C3%A8me_du_rendu_de_monnaie) avec un **algorithme glouton** qui est optimal pour les **systèmes de monnaies cannoniques** (comme l'euro).\n",
"\n",
"Mais si nous disposons des pièces : **4, 3 et 1**, pour un rendu de 6, l'algorithme glouton rendra 3 pièces (4+1+1) alors qu'une solution en 2 pièces existe (3+3).\n",
"\n",
"Nous allons programmer une fonction `rendu_monnaie` **récursive** pour trouver la **solution optimale et explorant toutes les possibilités**.\n",
"\n",
"L'idée est de lancer une recherche récursive en choisissant 1 pièce et de garder seulement la solution qui demande le moins de pièces pour la somme restante. Voici un exemple avec [4,3,1] et 8 :\n",
"- Je vais utiliser 1 pièce à tour de rôle : 4 puis je lance récursivement ma fonction avec [4,3,1] et 8-4 = 4. Puis je fais pareil avec les pièces 3 puis 1.\n",
"- Je sais ainsi que le nombre de pièces total pour chaque possibilité est le résultat de l'appel récursif + 1. Il me suffit donc de choisir la branche qui retourne le moins de pièces.\n",
"\n",
"💡 Et comme le programme est **récursif toutes les possibilités seront automatiquement explorée** pour donner une solution optimale."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"def rendu_monnaie(pieces: list, somme: int) -> list:\n",
" \"\"\" Return optimal coin's count for money back\n",
" Return None if no solution exists\n",
" pieces : list of int\n",
" >>> rendu_monnaie([], 5) is None\n",
" True\n",
" >>> rendu_monnaie([4,3], 1) is None\n",
" True\n",
" >>> rendu_monnaie([4,3], -1) is None\n",
" True\n",
" >>> rendu_monnaie([4,3], 5) is None\n",
" True\n",
" >>> rendu_monnaie([4,3], 6)\n",
" [3, 3]\n",
" >>> rendu_monnaie([4,3], 8)\n",
" [4, 4]\n",
" >>> rendu_monnaie([4,3,1], 6)\n",
" [3, 3]\n",
" >>> rendu_monnaie([4,3,1], 5)\n",
" [4, 1] \n",
" \"\"\"\n",
"\n",
"import doctest\n",
"doctest.testmod(optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE, verbose = False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Rendu de monnaie optimal et dynamique !\n",
"\n",
"La solution ci-dessus qui explore **toutes les possibilités** récursivement est séduisante mais si vous lancez `rendu_monnaie([4,3,1], 25)` avec l'affichage des appels vous allez constater que le nombre d'appels est considérable. Ce qui explique pourquoi `rendu_monnaie([4,3,1], 53)` a du mal à répondre dans un temps raisonnable...\n",
"\n",
"Nous allons donc améliorer notre algorithme en écrivant une fonction `rendu_dyn` avec la technique de la **programmation dynamique** en mémorisant les solutions déjà calculées pour les réutiliser au cours du calcul."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def rendu_dyn(pieces: list, somme: int) -> list:\n",
" \"\"\" Return optimal coin's count for money back\n",
" Return [] if no solution exists\n",
" pieces : list of POSITIVE int \n",
" >>> rendu_dyn([], 5)\n",
" []\n",
" >>> rendu_dyn([4,3], 1)\n",
" []\n",
" >>> rendu_dyn([4,3], 0)\n",
" []\n",
" >>> rendu_dyn([4,3], 5)\n",
" []\n",
" >>> rendu_dyn([4,3], 6)\n",
" [3, 3]\n",
" >>> rendu_dyn([4,3], 8)\n",
" [4, 4]\n",
" >>> rendu_dyn([4,3,1], 6)\n",
" [3, 3]\n",
" >>> rendu_dyn([4,3,1], 5)\n",
" [4, 1]\n",
" \"\"\"\n",
"\n",
"import doctest\n",
"doctest.testmod(optionflags=doctest.ELLIPSIS | doctest.NORMALIZE_WHITESPACE, verbose = False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Diviser pour régner : rotation d'une image d'un quart de tour en temps constant\n",
"\n",
"🤯 Faites l'exercice `Objectif BAC` du livre de NSI page 52. Le corrigé est disponible page 63."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"👏👏👏 Bravo ! 👏👏👏"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.1"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@@ -0,0 +1,15 @@
def combinaisons(n,p):
result = 1
if n>p and p>0:
result = combinaisons(n-1,p-1) + combinaisons(n-1,p)
return result
print(combinaisons(32,5))
def combinaisons2(n,p):
if n>p and p>0:
return combinaisons(n-1,p-1) + combinaisons(n-1,p)
else:
return 1
print(combinaisons2(32,5))

View File

@@ -0,0 +1,31 @@
from functools import lru_cache
from functools import cache
@cache
def steps_to(stair):
if stair == 1:
# You can reach the first stair with only a single step from the floor.
return 1
elif stair == 2:
# You can reach the second stair by jumping from the floor with a single two-stair hop or by jumping a single stair a couple of times.
return 2
elif stair == 3:
# You can reach the third stair using four possible combinations:
# 1. Jumping all the way from the floor
# 2. Jumping two stairs, then one
# 3. Jumping one stair, then two
# 4. Jumping one stair three times
return 4
else:
# You can reach your current stair from three different places:
# 1. From three stairs down
# 2. From two stairs down
# 2. From one stair down
# If you add up the number of ways of getting to those
# those three positions, then you should have your solution.
return steps_to(stair - 3) + steps_to(stair - 2) + steps_to(stair - 1)
print(steps_to(35))

View File

@@ -0,0 +1,30 @@
digraph Fibonnacci {
#bgcolor="transparent"
"fib(6)" -> {fib4 [label="fib(4)"] fib5 [label="fib(5)"]}
subgraph cluster1 {
style="rounded,dashed";
fib4 -> {fib2 [label="fib(2)"] fib3 [label="fib(3)"]}
subgraph cluster1 {
style="rounded,dotted";
fib3 -> {fib1 [label="fib(1)"] fib22 [label="fib(2)"]}
}
}
fib5 -> {fib33 [label="fib(3)"] fib44 [label="fib(4)"]};
subgraph cluster2 {
style="rounded,dotted";
fib33 -> {fib11 [label="fib(1)"] fib222 [label="fib(2)"]};
}
subgraph cluster3 {
style="rounded,dashed";
fib44 -> {fib2222 [label="fib(2)"] fib333 [label="fib(3)"]}
subgraph cluster4 {
style="rounded,dotted";
fib333 -> {fib111 [label="fib(1)"] fib22222 [label="fib(2)"]}
}
}
}

View File

@@ -0,0 +1,41 @@
from random import randint
nb_interrupteurs = 10
etats_interrupteurs = [_%2==1 for _ in range(nb_interrupteurs)]
etats_interrupteurs = [False for _ in range(nb_interrupteurs)]
etats_interrupteurs = [randint(0,1)==0 for _ in range(nb_interrupteurs)]
commutations = []
print(etats_interrupteurs)
def inverse_interrupteur(n: int):
global etats_interrupteurs
global commutations
#print("On inverse l'interrupteur", n)
commutations.append(n)
etats_interrupteurs[n-1] = not etats_interrupteurs[n-1]
def islight() -> bool:
global etats_interrupteurs
result = True
for etat_interrupteur in etats_interrupteurs:
if not etat_interrupteur:
result = False
break
return result
def cherche_commutations(n):
#print("commute", n)
if n == 1 and not islight():
inverse_interrupteur(n)
elif n > 1 and not islight():
cherche_commutations(n-1)
if not islight():
inverse_interrupteur(n)
if not islight():
cherche_commutations(n-1)
cherche_commutations(nb_interrupteurs)
print(etats_interrupteurs)
print(len(commutations))

View File

@@ -0,0 +1,38 @@
def multiplication_egyptienne(n: int, m: int) -> int:
assert n>=1 and m>=1
result = m
if n > 1:
if n % 2 == 0:
result = multiplication_egyptienne(n//2, m*2)
else:
result = m + multiplication_egyptienne(n-1, m)
return result
print(multiplication_egyptienne(7,5))
def multiplication_egyptienne2(n: int, m: int) -> int:
assert n>=1 and m>=1
if n == 1:
return m
elif n % 2 == 0:
return multiplication_egyptienne(n//2, m*2)
else:
return m + multiplication_egyptienne(n-1, m)
print(multiplication_egyptienne2(7,5))
def multiplication_egyptienne_iterative(n: int, m: int) -> int:
assert n > m
assert n>=1 and m>=1
result = 0
while n > 1:
if n % 2 != 0:
result += m
n = n-1
else :
n = n//2
m = m*2
result += m
return result
print(multiplication_egyptienne_iterative(7,5))

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 2.44.0 (0)
-->
<!-- Title: Fibonnacci Pages: 1 -->
<svg width="683pt" height="356pt"
viewBox="0.00 0.00 683.00 356.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 352)">
<title>Fibonnacci</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-352 679,-352 679,4 -4,4"/>
<g id="clust2" class="cluster">
<title>cluster1</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M20,-80C20,-80 239,-80 239,-80 245,-80 251,-86 251,-92 251,-92 251,-272 251,-272 251,-278 245,-284 239,-284 239,-284 20,-284 20,-284 14,-284 8,-278 8,-272 8,-272 8,-92 8,-92 8,-86 14,-80 20,-80"/>
</g>
<g id="clust4" class="cluster">
<title>cluster1</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M98,-88C98,-88 231,-88 231,-88 237,-88 243,-94 243,-100 243,-100 243,-200 243,-200 243,-206 237,-212 231,-212 231,-212 98,-212 98,-212 92,-212 86,-206 86,-200 86,-200 86,-100 86,-100 86,-94 92,-88 98,-88"/>
</g>
<g id="clust7" class="cluster">
<title>cluster2</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M271,-88C271,-88 404,-88 404,-88 410,-88 416,-94 416,-100 416,-100 416,-200 416,-200 416,-206 410,-212 404,-212 404,-212 271,-212 271,-212 265,-212 259,-206 259,-200 259,-200 259,-100 259,-100 259,-94 265,-88 271,-88"/>
</g>
<g id="clust9" class="cluster">
<title>cluster3</title>
<path fill="none" stroke="black" stroke-dasharray="5,2" d="M436,-8C436,-8 655,-8 655,-8 661,-8 667,-14 667,-20 667,-20 667,-200 667,-200 667,-206 661,-212 655,-212 655,-212 436,-212 436,-212 430,-212 424,-206 424,-200 424,-200 424,-20 424,-20 424,-14 430,-8 436,-8"/>
</g>
<g id="clust11" class="cluster">
<title>cluster4</title>
<path fill="none" stroke="black" stroke-dasharray="1,5" d="M514,-16C514,-16 647,-16 647,-16 653,-16 659,-22 659,-28 659,-28 659,-128 659,-128 659,-134 653,-140 647,-140 647,-140 514,-140 514,-140 508,-140 502,-134 502,-128 502,-128 502,-28 502,-28 502,-22 508,-16 514,-16"/>
</g>
<!-- fib(6) -->
<g id="node1" class="node">
<title>fib(6)</title>
<ellipse fill="none" stroke="black" cx="231" cy="-330" rx="30.59" ry="18"/>
<text text-anchor="middle" x="231" y="-326.3" font-family="Times,serif" font-size="14.00">fib(6)</text>
</g>
<!-- fib4 -->
<g id="node2" class="node">
<title>fib4</title>
<ellipse fill="none" stroke="black" cx="165" cy="-258" rx="30.59" ry="18"/>
<text text-anchor="middle" x="165" y="-254.3" font-family="Times,serif" font-size="14.00">fib(4)</text>
</g>
<!-- fib(6)&#45;&gt;fib4 -->
<g id="edge1" class="edge">
<title>fib(6)&#45;&gt;fib4</title>
<path fill="none" stroke="black" d="M216.68,-313.81C207.77,-304.36 196.15,-292.04 186.19,-281.48"/>
<polygon fill="black" stroke="black" points="188.7,-279.03 179.29,-274.16 183.61,-283.84 188.7,-279.03"/>
</g>
<!-- fib5 -->
<g id="node3" class="node">
<title>fib5</title>
<ellipse fill="none" stroke="black" cx="337" cy="-258" rx="30.59" ry="18"/>
<text text-anchor="middle" x="337" y="-254.3" font-family="Times,serif" font-size="14.00">fib(5)</text>
</g>
<!-- fib(6)&#45;&gt;fib5 -->
<g id="edge2" class="edge">
<title>fib(6)&#45;&gt;fib5</title>
<path fill="none" stroke="black" d="M250.94,-315.83C267.33,-305.01 290.74,-289.55 309.01,-277.49"/>
<polygon fill="black" stroke="black" points="311.09,-280.3 317.51,-271.87 307.24,-274.46 311.09,-280.3"/>
</g>
<!-- fib2 -->
<g id="node4" class="node">
<title>fib2</title>
<ellipse fill="none" stroke="black" cx="47" cy="-186" rx="30.59" ry="18"/>
<text text-anchor="middle" x="47" y="-182.3" font-family="Times,serif" font-size="14.00">fib(2)</text>
</g>
<!-- fib4&#45;&gt;fib2 -->
<g id="edge3" class="edge">
<title>fib4&#45;&gt;fib2</title>
<path fill="none" stroke="black" d="M142.38,-245.7C125.45,-237.01 101.88,-224.42 82,-212 79.21,-210.26 76.35,-208.38 73.52,-206.46"/>
<polygon fill="black" stroke="black" points="75.44,-203.53 65.24,-200.67 71.43,-209.27 75.44,-203.53"/>
</g>
<!-- fib3 -->
<g id="node5" class="node">
<title>fib3</title>
<ellipse fill="none" stroke="black" cx="165" cy="-186" rx="30.59" ry="18"/>
<text text-anchor="middle" x="165" y="-182.3" font-family="Times,serif" font-size="14.00">fib(3)</text>
</g>
<!-- fib4&#45;&gt;fib3 -->
<g id="edge4" class="edge">
<title>fib4&#45;&gt;fib3</title>
<path fill="none" stroke="black" d="M165,-239.7C165,-231.98 165,-222.71 165,-214.11"/>
<polygon fill="black" stroke="black" points="168.5,-214.1 165,-204.1 161.5,-214.1 168.5,-214.1"/>
</g>
<!-- fib33 -->
<g id="node8" class="node">
<title>fib33</title>
<ellipse fill="none" stroke="black" cx="337" cy="-186" rx="30.59" ry="18"/>
<text text-anchor="middle" x="337" y="-182.3" font-family="Times,serif" font-size="14.00">fib(3)</text>
</g>
<!-- fib5&#45;&gt;fib33 -->
<g id="edge7" class="edge">
<title>fib5&#45;&gt;fib33</title>
<path fill="none" stroke="black" d="M337,-239.7C337,-231.98 337,-222.71 337,-214.11"/>
<polygon fill="black" stroke="black" points="340.5,-214.1 337,-204.1 333.5,-214.1 340.5,-214.1"/>
</g>
<!-- fib44 -->
<g id="node9" class="node">
<title>fib44</title>
<ellipse fill="none" stroke="black" cx="463" cy="-186" rx="30.59" ry="18"/>
<text text-anchor="middle" x="463" y="-182.3" font-family="Times,serif" font-size="14.00">fib(4)</text>
</g>
<!-- fib5&#45;&gt;fib44 -->
<g id="edge8" class="edge">
<title>fib5&#45;&gt;fib44</title>
<path fill="none" stroke="black" d="M358.94,-245.33C375.73,-236.35 399.42,-223.56 420,-212 424.29,-209.59 428.8,-207.01 433.23,-204.46"/>
<polygon fill="black" stroke="black" points="435.18,-207.38 442.08,-199.33 431.67,-201.32 435.18,-207.38"/>
</g>
<!-- fib1 -->
<g id="node6" class="node">
<title>fib1</title>
<ellipse fill="none" stroke="black" cx="125" cy="-114" rx="30.59" ry="18"/>
<text text-anchor="middle" x="125" y="-110.3" font-family="Times,serif" font-size="14.00">fib(1)</text>
</g>
<!-- fib3&#45;&gt;fib1 -->
<g id="edge5" class="edge">
<title>fib3&#45;&gt;fib1</title>
<path fill="none" stroke="black" d="M155.72,-168.76C150.95,-160.4 145.01,-150.02 139.63,-140.61"/>
<polygon fill="black" stroke="black" points="142.51,-138.58 134.5,-131.63 136.43,-142.05 142.51,-138.58"/>
</g>
<!-- fib22 -->
<g id="node7" class="node">
<title>fib22</title>
<ellipse fill="none" stroke="black" cx="204" cy="-114" rx="30.59" ry="18"/>
<text text-anchor="middle" x="204" y="-110.3" font-family="Times,serif" font-size="14.00">fib(2)</text>
</g>
<!-- fib3&#45;&gt;fib22 -->
<g id="edge6" class="edge">
<title>fib3&#45;&gt;fib22</title>
<path fill="none" stroke="black" d="M174.05,-168.76C178.7,-160.4 184.49,-150.02 189.73,-140.61"/>
<polygon fill="black" stroke="black" points="192.92,-142.07 194.73,-131.63 186.81,-138.67 192.92,-142.07"/>
</g>
<!-- fib11 -->
<g id="node10" class="node">
<title>fib11</title>
<ellipse fill="none" stroke="black" cx="298" cy="-114" rx="30.59" ry="18"/>
<text text-anchor="middle" x="298" y="-110.3" font-family="Times,serif" font-size="14.00">fib(1)</text>
</g>
<!-- fib33&#45;&gt;fib11 -->
<g id="edge9" class="edge">
<title>fib33&#45;&gt;fib11</title>
<path fill="none" stroke="black" d="M327.95,-168.76C323.3,-160.4 317.51,-150.02 312.27,-140.61"/>
<polygon fill="black" stroke="black" points="315.19,-138.67 307.27,-131.63 309.08,-142.07 315.19,-138.67"/>
</g>
<!-- fib222 -->
<g id="node11" class="node">
<title>fib222</title>
<ellipse fill="none" stroke="black" cx="377" cy="-114" rx="30.59" ry="18"/>
<text text-anchor="middle" x="377" y="-110.3" font-family="Times,serif" font-size="14.00">fib(2)</text>
</g>
<!-- fib33&#45;&gt;fib222 -->
<g id="edge10" class="edge">
<title>fib33&#45;&gt;fib222</title>
<path fill="none" stroke="black" d="M346.28,-168.76C351.05,-160.4 356.99,-150.02 362.37,-140.61"/>
<polygon fill="black" stroke="black" points="365.57,-142.05 367.5,-131.63 359.49,-138.58 365.57,-142.05"/>
</g>
<!-- fib2222 -->
<g id="node12" class="node">
<title>fib2222</title>
<ellipse fill="none" stroke="black" cx="463" cy="-114" rx="30.59" ry="18"/>
<text text-anchor="middle" x="463" y="-110.3" font-family="Times,serif" font-size="14.00">fib(2)</text>
</g>
<!-- fib44&#45;&gt;fib2222 -->
<g id="edge11" class="edge">
<title>fib44&#45;&gt;fib2222</title>
<path fill="none" stroke="black" d="M463,-167.7C463,-159.98 463,-150.71 463,-142.11"/>
<polygon fill="black" stroke="black" points="466.5,-142.1 463,-132.1 459.5,-142.1 466.5,-142.1"/>
</g>
<!-- fib333 -->
<g id="node13" class="node">
<title>fib333</title>
<ellipse fill="none" stroke="black" cx="542" cy="-114" rx="30.59" ry="18"/>
<text text-anchor="middle" x="542" y="-110.3" font-family="Times,serif" font-size="14.00">fib(3)</text>
</g>
<!-- fib44&#45;&gt;fib333 -->
<g id="edge12" class="edge">
<title>fib44&#45;&gt;fib333</title>
<path fill="none" stroke="black" d="M479.37,-170.5C490.49,-160.64 505.39,-147.44 517.87,-136.38"/>
<polygon fill="black" stroke="black" points="520.49,-138.74 525.65,-129.49 515.85,-133.5 520.49,-138.74"/>
</g>
<!-- fib111 -->
<g id="node14" class="node">
<title>fib111</title>
<ellipse fill="none" stroke="black" cx="541" cy="-42" rx="30.59" ry="18"/>
<text text-anchor="middle" x="541" y="-38.3" font-family="Times,serif" font-size="14.00">fib(1)</text>
</g>
<!-- fib333&#45;&gt;fib111 -->
<g id="edge13" class="edge">
<title>fib333&#45;&gt;fib111</title>
<path fill="none" stroke="black" d="M541.75,-95.7C541.64,-87.98 541.51,-78.71 541.39,-70.11"/>
<polygon fill="black" stroke="black" points="544.89,-70.05 541.24,-60.1 537.89,-70.15 544.89,-70.05"/>
</g>
<!-- fib22222 -->
<g id="node15" class="node">
<title>fib22222</title>
<ellipse fill="none" stroke="black" cx="620" cy="-42" rx="30.59" ry="18"/>
<text text-anchor="middle" x="620" y="-38.3" font-family="Times,serif" font-size="14.00">fib(2)</text>
</g>
<!-- fib333&#45;&gt;fib22222 -->
<g id="edge14" class="edge">
<title>fib333&#45;&gt;fib22222</title>
<path fill="none" stroke="black" d="M558.16,-98.5C569.14,-88.64 583.85,-75.44 596.17,-64.38"/>
<polygon fill="black" stroke="black" points="598.75,-66.77 603.86,-57.49 594.08,-61.56 598.75,-66.77"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB