Il s'agit d'une figure construite récursivement. On peut définir S(n,c) ainsi :
n est le niveau de détails souhaité,c est la taille du côtéLa construction nous indique que :
n = 0 on a un simple triangle pleinn = 1, S(1, c) est constitué de 3 triangles inférieurs : S(0, c/2)n = 2, S(2, c) est constitué de 3 triangles inférieurs : S(1, c/2)n > 1, S(n,c) est constitué de 3 figures S(n-1, c/2).
On peut faire le tracer en utilisant le module turtle :
from turtle import * speed(100) pensize(1) # taille du tracé setheading(0) # orientation vers l'est # votre programme ici # fin du programme exitonclick()
Quelques commandes dans ce TD. Vous pouvez aussi utiliser la documentation du module turtle.
Écrivez la fonction S(n,c) faisant le tracé du triangle de Sierpinski. Faites l'essai par exemple avec S(5,200).
Sur le même principe, flocon de Koch
Dans ce TD, on vous décrit le problème des tours de Hanoï.
Un solution très simple de ce problème passe par une fonction récursive.
On veut déplacer une pile de N cylindres de la position A à la position B. Pour cela, il faut :
Implémentez cette solution.
Dans cet exercice nous avons vu des exemples de fonctions récursives permettant de calculer la hauteur ou la taille d'un arbre.
Une liste chaînée peut être vue comme un arbre spécial – un nœud n'a qu'un enfant – et on pourrait donc appliquer la même méthode pour obtenir la longueur d'une liste.
Ce problème a été vu en première dans le cadre de l'algorithme glouton. Rappelons-en le principe.
Exemple : On dispose d'un sac d'une capacité de C = 15 kg et de la liste d'objets suivants :
| nom | Valeur | Poids |
|---|---|---|
| A | 80 | 8 |
| B | 32 | 2 |
| C | 20 | 5 |
| D | 126 | 14 |
| E | 5 | 1 |
| F | 18 | 6 |
Quel objet doit-on prendre pour maximiser la valeur contenue dans le sac ?
Supposons que j'écrive une fonction meilleur_sac(C, objets) où objets est le tableau précédent. Pour résumer, on pourra noter [ABCDEF] le tableau complet et [CDEF] le même tableau duquel on
aurait enlevé les lignes A et B.
Supposons que je calcule meilleur_sac(15, [ABCDEF]). Voici le raisonnement récursif que l'on va tenir :
meilleur_sac(15, [BCDEF]).meilleur_sac(7, [BCDEF]).
Implémentez la fonction meilleur_sac et donnez la solution du problème.
FONCTION meilleur_sac
ENTRÉES:
c : capacité restante
items: liste des items que l'on peut choisir
SORTIE: le sac formé d'un choix dans la liste items,
qui forme le meilleur sac possible avec la capacité c
DÉBUT
SI items vide ou c < = 0 ALORS
dans ce cas, on ne peut rien mettre dans le sac donc
RENVOYER sac vide
FIN SI
soit A le premier item parmi les items à choisir
(A existe forcément puisque si items vide, on aurait déjà fini)
soient items_sans_A la liste des items dont on a ôté A
on forme un premier essai de sac, appelé sac1. Dans ce sac on place A
il reste donc c - poids(A) de capacité que l'on peut remplir avec items_sans_A
en résumé, sac1 = A + meilleur_sac(c - poids(A), items_sans_A)
à noter : il se pourrait que ce sac ne soit pas valide. En effet, il se peut
que poids(A) > c.
on forme un autre sac, sac2, qui ne contient pas A. On dispose donc de la totalité
de la capacité pour former un sac au mieux avec les autres items.
donc sac2 = meilleur_sac(c, items_sans_A)
à noter : ce sac est forcément valide.
maintenant il faut choisir le meilleur sac entre sac1 et sac2 :
SI le sac1 est valide et qu'il a une valeur plus grande que sac2 ALORS
RENVOYER sac1
SINON
RENVOYER sac2
FIN
FIN
Cette façon de faire est élégante. Le code est simple, facile à écrire et à comprendre. On a par contre un peu de mal à savoir si cela occasionnera beaucoup de calculs. Il se pourrait que l'on fasse plusieurs fois les mêmes calculs et que l'on perde du temps. Cet aspect est abordé avec la programmation dynamique.