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