T.P. 1 Révisions sur les chaˆınes de caract`eres, listes, et

Transcription

T.P. 1 Révisions sur les chaˆınes de caract`eres, listes, et
T.P. 1 Révisions sur les chaı̂nes de caractères, listes, et
introductions aux graphes... avec un sujet de recherche
pour les vacances....
Ce T.P. comprends deux parties indépendantes.
1
Manipulations de chaı̂nes de caractères : le système MIU
Dans cet exercice, on appelle mot une chaı̂ne de caractères.
Les mots que nous allons considérer n’utilisent que les trois lettres M,I et U.
Le but du jeu est de fabriquer des mots nouveaux à partir, au départ, du seul mot MI.
Pour cela, il y a quatre règles (et quatre seulement) qui vous permettent d’agrandir votre
collection de mots. Vous pouvez appliquer ces règles dans l’ordre de votre choix.
R1 : Si vous possédez un mot se terminant par I, vous pouvez lui rajouter un U à la fin.
P.ex. avec MI vous pouvez faire MIU
R2 : Si vous avez un mot de la forme Mx où x remplace n’importe quelle chaı̂ne de lettres
jusqu’à la fin du mot, vous pouvez faire le mot Mxx.
P.ex. avec MIU vous pouvez faire MIUIU et avec MI vous pouvez faire MII
R3 : Si dans un mot vous avez III vous pouvez remplacer ce III par U.
R4 Si dans un mot vous avez UU à n’importe quel endroit de la chaı̂ne vous pouvez supprimer
ce UU.
A titre d’exemple voici quelques applications de ces règles, à partir du seul axiome MI
Exple 1 : M I Ð→ M II Ð→ M IIII Ð→ M U I Ð→ M U IU I.
R2
R2
R3
R2
Exple 2 : M I Ð→ M II Ð→ M IIII Ð→ M IIIIU Ð→ M U IU Ð→ M U IU U IU Ð→ M U IIU
R2
R2
R1
R3
R2
R4
Ou bien seulement avec M I Ð→ M II Ð→ M IIII Ð→ M IIIIIIII Ð→ M U IIU .
R2
R2
R2
R3
a) Ecrire deux fonctions R1 et R2 qui prennent une chaı̂ne de caractères S en argument et
retournent la chaı̂ne obtenue par l’application des règles R1 et R2 à S.
Remarques : ● Noter que si S ne se termine pas par un I, la fonction R1 ne retournera
rien, c’est-à-dire retournera un None.
● Tous les mots qu’on manipule ici commencent par un M. Pour R2 on supposera déjà que
le mot passé en argument commence par M.
b) Ecrire une fonction R3(S,i) qui prend en argument une chaı̂ne de caractères S et un indice
i et qui regarde si la chaine S contient la chaı̂ne III aux entrées S[i], S[i+1], S[i+2] et
si c’est le cas, retourne la chaı̂ne de caractères déduite de S en remplaçant ces III suivant
la règle 3.
c) Ecrire une fonction appliqueR3 qui prend en argument une chaine de caractères S et qui
renvoie la liste de tous les mots qu’on peut obtenir en appliquant une seule fois R3 à S.
d) Faire de même une fonction R4(S,i) et une fonction appliqueR4(S).
e) Ecrire enfin une fonction MIU(n) qui prend en argument un entier n et renvoie la liste de
tous les mots qu’on peut obtenir à partir de MI en appliquant n fois les règles du système
comme indiqué dans l’arbre suivant :
1
Ainsi par exemple :
>>> MIU(1)
[’MI’, ’MIU’, ’MII’]
>>> MIU(2)
[’MI’, ’MIU’, ’MII’, ’MIUIU’, ’MIIU’, ’MIIII’]
2
2.1
Initiations aux graphes
Introduction : deux codages des graphes
Informellement, un graphe est un ensemble S de points (sommets du graphe) pouvant être reliés
par des arêtes.
Un exemple simple de graphe, dont on a numéroté les sommets de 1 à 6 :
Une façon de coder informatiquement le présence ou non d’arête entre deux sommets du graphe
est d’utiliser une matrice d’adjance M = (mi,j ) où mi,j = 1 ssi il y a une arête entre le sommet
numéro i et le sommet numéro j, et sinon mi,j = 0.
⎛ 0 1 1 0 0 0⎞
⎜ 1 0 1 1 0 0⎟
⎟
⎜
⎜ 1 1 0 0 1 0⎟
⎟
Ainsi sur l’exemple précédent, la matrice d’adjacence sera : ⎜
⎜ 0 1 0 0 1 0⎟
⎟
⎜
⎜ 0 0 1 1 0 1⎟
⎟
⎜
⎝ 0 0 0 0 1 0⎠
Une autre façon de coder un graphe est de se donner pour chaque sommet, la liste des numéros
de ses voisins. Cette liste s’appelle la liste d’incidence.
Sur l’exemple précédent, la liste d’incidence serait :
L=[[1, 2], [0, 2, 3], [0, 1, 4], [1, 4], [2, 3, 5], [4]]
Travail à faire : écrire deux fonctions LI et MA qui permettent resp. d’obtenir resp. la liste
d’incidence si on lui donne la matrice d’adjacence et inversement.
2.2
Un joli graphe à représenter graphiquement en Python
On va représenter un graphe à 25 sommets, qui est assez ≪ régulier ≫, en ce sens que presque
tous les sommets sont reliés à trois voisins, sauf ceux des bords.
On donne d’abord la façon choisie pour représenter les 25 sommets :
import matplotlib.pyplot as plt
import random as rd
plt.axis("off")
2
plt.clf()
Vstr="ABCDEFGHIJKLMNOPQRSTUVWXY"
N=5
k=0
for i in range(N):
for j in range(N):
x=100*i+70*rd.random() # rd.random renvoie un flottant dans [0,1)
y=100*j+70*rd.random()
plt.plot(x,y,’ko’)
plt.text(x+7,y+7,Vstr[k])
k+=1
ce qui donne un placement des sommets qui ne sera pas trop loin de l’exemple suivant :
Compléter ce code pour obtenir le tracé des arêtes suivantes (ce qui demande déjà de comprendre
la règle d’établissement d’une arête entre deux sommets de ce graphe particulier autrement dit, la
matrice d’adjacence).
N.B. La matrice d’adjacente est 25 × 25 : vous n’avez pas le droit de la rentrer à la main ! Il y
a une ≪ règle de construction ≫ à découvrir ici.
3
Rappel 1 : il peut être pratique de se rappeler qu’on peut fabriquer une matrice de taille n
remplies de zéros comme suit : M=[[ 0 for j in range(n)] for i in range(n)]
Rappel 2 : pour tracer un segment entre (x, y) et (x′ , y ′ ) : plt.plot( [x,x’],[y,y’])
2.3
La notion de parcours (en largeur) d’un graphe
Un premier problème, quand on n’a que les yeux d’un ordinateur, est de savoir si un graphe est
connexe c’est-à-dire si l’on peut aller de n’importe quel sommet à n’importe quel autre.
La méthode suivante, dite parcours en largeur du graphe, va ≪ colorier en noir ≫ tous les sommets
qu’on peut atteindre à partir d’un sommet s0.
On va définir une fonction Parcours(G,s0) où G est un graphe (représenté, comme vous le
préférez par une matrice d’adjacence ou une liste d’incidence) et s0 le numéro d’un sommet.
En pseudo-code l’algorithme fait la chose suivante :
On considère qu’au départ tous les sommets sont blancs.
Colorier s0 en gris.
Tant qu’il y a un sommet gris, prendre le premier de la liste des coloriés en
gris qu’on note s :
Pour chaque voisin v de s :
Si v est blanc :
Colorier v en gris.
Colorier s en noir
Renvoyer la liste des noirs.
La liste des noirs sera la liste des sommets atteignables à partir de s0. Tester cela sur des
exemples à la main, puis écrire une fonction python parcours(G).
Essayer votre algorithme sur un graphe non connexe, comme par exemple celui qui suit... que
vous gagnerez à rentrer par sa liste d’incidence....
4
2.4
Algorithme de Dijkstra (pour les vacances ?)
On se donne cette fois un graphe représentant par exemple des routes entre des villes, et les
arêtes sont porteuses d’une information supplémentaire qui est la distance entre ces villes (disons
en km). On modifie la matrice d’adjacence pour qu’elle contienne à la place de 1 ces distances.
Par exemple :
⎛0⎞
⎜76⎟
⎜ ⎟
⎜0⎟
⎟
La première colonne de la matrice d’adjacence est ⎜
⎜ 0 ⎟.
⎜ ⎟
⎜0 ⎟
⎜ ⎟
⎝56⎠
Noter qu’il est facile d’adapter la fonction LI pour qu’elle donne encore la liste d’incidence d’un
tel graphe (sans donner les kilométrages).
L’algorithme de Dijkstra prend en entrée une telle matrice d’adjacence et un sommet s0 et va
renvoyer pour chaque sommet s la distance minimale entre s0 et s autrement dit, les sommets
étant numérotés, la liste L des distances minimales, L[i] étant la distance minimale entre s0 et i.
Le principe de l’algorithme est le suivant :
Listedistance est initialisée avec toutes les valeurs à float(’inf’) c’est à dire l’infini.
On colorie s0 en gris
On met Listedistance[s0] à 0
Tant qu’il y a un sommet gris, on prend celui ayant la distance minimale dans Listedistance
qu’on note s:
5
Pour chaque voisin v de s:
Si v est blanc :
Colorier v en gris
Si v est gris:
Mettre à jour la Listedistance[v] en comparant la valeur courante
Listedistance[s] + la distance entre v et s
Colorier s en noir.
Renvoyer Listedistance
Cet algorithme est décrit sur un exemple dans Wikipédia dont voici le début
6
à
7

Documents pareils