X Informatique MP 2006

Thème de l'épreuve Dictionnaires
Principaux outils utilisés parcours d'arbre, programmation récursive

Corrigé

 : 👈 gratuite pour tous les corrigés si tu crées un compte
👈 l'accès aux indications de tous les corrigés ne coûte que 5 € ⬅ clique ici
👈 gratuite pour tous les corrigés si tu crées un compte
- - - - - - - - - - - - - - -

Énoncé complet

(télécharger le PDF)
                 

Rapport du jury

(télécharger le PDF)
              

Énoncé obtenu par reconnaissance optique des caractères


ÉCOLE POLYTECHNIQUE FILIÈRE MP
COEÏFDÛPJINÜNÔROEAÀCÈHQEÜE

CONCOURS D'ADMISSION 2006

COMPOSITION D'INFORMATIQUE

(Durée : 4 heures)

L'utilisation des calculatrices n'est pas autorisée pour cette épreuve.

Le langage de programmation choisi par le candidat doit être spécifié en tête 
de la copie.

***

Dictionnaires

On attachera une grande importance à la concision, a la clarté, et a la 
précision de la rédaction.

Dans tout ce problème, on s'intéressera a des structures de données pouvant 
représenter un
ensemble de mots, dont l'archétype est un dictionnaire, tel qu'il est utilisé 
dans un correcteur

orthographique.

La première partie de ce problème introduit la structure de données permettant 
de représenter
des mots. Les trois parties suivantes étudient une structure de données 
permettant de représenter
de façon efficace un dictionnaire par partage de préfixes. Cette structure de 
données s'appelle trie
et deux façons de l'implanter sont proposées. La cinquième partie résout la 
recherche du mot le plus
long. La sixième et dernière partie s'intéresse à la recherche d'anagrammes.

Partie I. Mots

Étant donné un alphabet A, contenant un nombre fini de lettres (typiquement 
26), on rappelle
qu'un mot est une suite finie d'éléments de A, et que l'ensemble des mots est 
noté A*.

Pour les réponses aux questions ci--dessous, afin qu'elles ne dépendent pas de 
l'alphabet choisi,
on supposera définies une constante entière N qui est le cardinal de 
l'alphabet, et une fonction
lettre qui prend en entrée un entier 72 compris entre 1 et N et qui écrit la 
z"èmEUR lettre de A. De
plus, lettre(0) écrit un espace, et lettre(--1) fait passer l'impression a la 
ligne suivante.

On définit un type mot permettant de représenter un mot sous la forme d'une 
liste d'entiers
strictement positifs (les indices des lettres du mot). Selon le contexte, le 
parcours de la liste donnera
les lettres du mot de gauche a droite (surnommé motGD) ou bien de droite a 
gauche (surnommé
motDG). Cette seconde option sera choisie lorsque le rajout d'une lettre en fin 
de mot devra se faire
en temps constant.

(* Caml *) {Pascal}

type mot = "Cellule; Cellule = record

type mot == int list ; ; _ _
lettre:1nteger; su1te:mot; end;
En Pascal la liste vide est nil et l'on pourra utiliser la fonction suivante 
pour construire des mots :

function nouveauMot(czinteger; u:mot) : mot;
var vzmot; begin new(v); v".lettre := c; v".suite := u; nouveauMot := v end;

Question 1 Définir une fonction imprimer qui imprime un mot de type motDG et 
passe a la ligne.
Par exemple appeler cette fonction sur la liste <1, 2, 3} avec l'alphabet usuel affiche cba suivi d'un passage a la ligne. (* Caml *) imprimer : mot --> unit

{ Pascal }

procedure imprimer (uzmot);

Question 2 Définir une fonction inverseDe qui transforme un mot de type motDG 
en un type
motGD, et réciproquement. Par exemple (1, 2, 3) devient (3,2,1).

(* Caml *)

inverseDe : mot --> mot

{ Pascal }

function inverseDe (uzmot) : mot;

Partie II. Dictionnaires

Pour simplifier les structures de données, on ajoute à l'alphabet A une lettre 
de terminaison, '
notée $. À tout mot dans A* on associe le mot de A*{$} obtenu en rajoutant un $ 
à la fin du mot;
ainsi, aucun mot du dictionnaire n'est préfixe d'un autre.

On représentera un dictionnaire au moyen de la struc--
ture de données appelée trie, qui est un arbre dont chaque

noeud a un nombre arbitraire de fils, et dont les branches $ . $

sont étiquetées. . , . $ .
Chaque branche de l'arbre est étiquetée par un élément " S . $ .

de A, sauf les branches qui mènent à une feuille et qui sont . . .

étiquetées par $. De plus, les étiquettes des branches is- "' i $ .

sues d'un même noeud sont toutes distinctes. L'ensemble . . . . e . $$ . $

des mots présents dans le dictionnaire est exactement l'en-- S . .

semble des mots qu'on obtient en listant les étiquettes vues ... . $ .

pendant un parcours de la racine jusqu'à une feuille. Voici 9 . $$ .

un exemple de trie, pour le dictionnaire { ame, ames, amen, . n . $ . $ .

amer, ami, amis, amie, amies, ane, anes, annee, annees }. . e . e . S . $ .

(Pour simplifier, les accents sont ignorés).
Plusieurs implantations des tries sont possibles.

Dans cette partie, on choisira d'utiliser une structure tabuléc : Puisqu'on 
peut identifier par leurs
étiquettes les branches issues d'un même noeud, chaque noeud contiendra un 
tableau indicé de 0 a
N, dont la case d'indice fl indique le sous--arbre issu de la branche 
d'étiquette i, ou bien l'arbre vide
si cette branche n'est pas présente.

On définit le type dictTab qui permet de représenter un dictionnaire tabulé.

(* Caml *) {Pascal}
type dictTab = type tabN = array[0..N] of dictTab;
VideT ! dictTab = "NoeudT;
NoeudT of dictTab vect ;; NoeudT = record fils:tabN; end;

En Pascal l'arbre vide est représenté par nil et l'on pourra utiliser le 
constructeur suivant :

function nouveauDictTab(var a: tabN) : dictTab;
var r:dictTab; begin new(r); r".fils := &; nouveauDictTab := r end;

Question 3

a) Décrire la représentation tabulée du dictionnaire vide et celle du 
dictionnaire contenant comme
unique élément le mot vide.

b) Prouver qu'une valeur de type dictTab représente un dictionnaire tabulé si, 
et seulement si,
les feuilles sont exactement les noeuds rattachés à leur père par une branche 
d'étiquette $. Cette
propriété pourra être nommée cohérence d'une valeur de type dictTab.

Question 4 Écrire la fonction imprimerDictTab qui prend en argument un 
dictionnaire tabulé
et écrit successivement tous les mots du dictionnaire (il s'agit bien 
d'afficher a l'écran les mots du

dictionnaire, et non pas d'en retourner la liste).

(* Caml *) {Pascal}
imprimerDictTab : dictTab --> unit procedure imprimerDictTab (dzdictTab);

La principale opération utile pour la correction orthographique est le test 
d'appartenance au
dictionnaire.

Question 5 Écrire la fonction estDansDictTab qui prend en argument un mot de 
type motGD
et un dictionnaire tabulé, et qui détermine si le mot est dans le dictionnaire. 
La réponse doit être
donnée par la valeur de retour de la fonction.

(* Caml *) {Pascal}
estDansDictTab : function estDansDictTab (uzmot, d:dictTab)
mot --> dictTab --> bool : boolean;

Une autre opération importante pour la correction orthographique est 
l'insertion d'un nouveau
mot dans le dictionnaire.

Question 6 Écrire la fonction aj outADictTab qui prend en argument un mot u de 
type motGD
et un dictionnaire tabulé et qui retourne le dictionnaire modifié après 
insertion du mot a.

(* Caml *) {Pascal}
ajoutADietTab : function ajoutADictTab (uzmot, d:dictTab)
mot --> dictTab --> dictTab : dictTab;

Partie III. Dictionnaire binaire

Une autre implantation est la structure binaire. Il s'agit
de faire descendre les étiquettes des branches vers les fils
puis d'utiliser l'isomorphisme entré les arbres dont les noeuds
ont un nombre arbitraire de fils (ordonnés), et les arbres
binaires. L'arbre binaire se construit ainsi : dans la liste des @ ° @
fils d'un noeud, le premier fils devient le fils gauche de son @ 9 © © © @
père, et chacun des fils suivants devient le fils droit de son @ © @ @
frère immédiatement précédent; enfin, on fait disparaître la @
rac1ne. @

On définit le type dictBin qui permet de représenter un dictionnaire binaire.

(* Caml *) {Pascal}
type dictBin = type dictBin = "NoeudB; NoeudB = record
VideB l NoeudB of etiq:integer; filstdictBin;
dictBin * int * dictBin ;; filsD:dictBin; end;

En Pascal l'arbre vide est représenté par nil et l'on pourra utiliser le 
constructeur suivant :

function nouveauDictBin(czinteger; a,b:dictBin) : dictBin;
var r:dictBin; begin new(r); r".etiq = c;
r".filsG := a; r".filsD := b; nouveauDictTab := r end;

Question 7 Expliquer pourquoi on fait disparaître la racine. Décrire la 
représentation binaire du
dictionnaire vide et celle du dictionnaire contenant comme unique élément le 
mot vide.

Question 8 Ecrire la fonction imprimerDictBin qui prend en argument un 
dictionnaire binaire
et écrit successivement tous les mots du dictionnaire.

(* Caml *) {Pascal}

imprimerDictBin : dictBin --> unit procedure imprimerDictBin (dzdictBin);

Pour les deux prochaines questions, deux réponses @
sont possibles, selon qu'on impose ou non que les éti-- @
quettes parcourues en descendant vers les fils droits
soient par ordre croissant des indices des lettres dans
l'alphabet. Il faudra choisir la solution supposant que
les fils droits ne sont pas triés en ordre croissant.

Ainsi le dictionnaire binaire ci--contre peut aussi @
représenter le dictionnaire { ame, ames, amen, amer, @
ami, amis, amie, amies, ane, anes, annee, annees }.

© EUR 9

Question 9 Écrire la fonction estDansDictBin qui prend en argument un mot de 
type motGD et
un dictionnaire binaire et qui détermine si le mot est dans le dictionnaire.

(* Caml *) {Pascal}
estDansDictBin : function estDansDictBin (u:mot, d:dictBin)
mot -> dictBin --> bool : boolean;

Question 10 Écrire la fonction aj outADictBin qui prend en argument un mot de 
type motGD et
un dictionnaire binaire et qui modifie le dictionnaire pour y ajouter le mot.

(* Caml *) {Pascal}

ajoutADictBin : function ajoutADictBin (uzmot; d:dictBin)
mot --> dictBin -> dictBin : dictBin;

Partie IV. Comparaison des coûts; conversion de représentations

On se place dans le cas où le dictionnaire manipulé contient n5 mots de 
longueur moyenne n.

Question 11

a) Donner un encadrement du nombre de sommets S en fonction de n et N. Calculer 
en fonction
de S le coût mémoire de chacune des deux représentations, et comparer.

b) Évaluer et comparer la complexité en temps du test d'appartenance et de 
l'ajout d'un mot
de longueur EUR , pour chacune des deux représentations.

Question 12 Écrire la fonction tabVersBin qui prend en argument un dictionnaire 
tabulé et
retourne le dictionnaire binaire équivalent.

(* Caml *)
tabVersBin : dictTab --> dictBin

{ Pascal }
function tabVersBin (dzdictTab) : dictBin;

Question 13 Écrire la fonction binVersTab qui prend en argument un dictionnaire 
binaire et
retourne le dictionnaire tabulé équivalent.

(* Caml *)
binVersTab : dictBin --> dictTab

{ Pascal }
function binVersTab (d:dictBin) : dictTab;

Partie V. Le mot le plus long

Il s'agit, étant donné un chevalet rempli de lettres, de trouver tous les mots 
du dictionnaire qu'on
peut composer à l'aide de ces lettres, et en particulier le(s) plus long(s) 
d'entre eux. Le dictionnaire
est représenté par un trie. Le choix de l'une des deux implantations ci--dessus 
est libre.

Question 14 Écrire la fonction imprimerMotsDans qui prend en argument un mot et 
un diction-
naire et qui retourne la liste des mots de ce dictionnaire composés de lettres 
du mot fourni en entrée.
Une même lettre pourra être utilisée au plus le nombre de fois où elle apparaît 
dans le mot initial.

Estimer la complexité de cette fonction.
(* Caml *) {Pascal}

imprimerMotsDans :

_ _ procedure imprimerMotsDans (dzdictXXX, u:mot);
d1ctXXX --> mot --> un1t

Partie VI. Anagrammes

Un mot est un anagramme d'un mot a donné s'il est composé de mots du 
dictionnaire et si cha--
cune de ses lettres apparaît le même nombre de fois que dans u. Par exemple si
a : cceeeehillnoopqtuy, le mot a a pour anagrammes, entre autres, 
ecole...polytechnique,
hellenique...type...coco ou encore pole...cyclone...ethique. Les mots du 
dictionnaire sont sépa--
rés dans un même anagramme par le caractère ... imprimé en appelant la fonction 
lettre avec le
paramètre O.

Question 15 Ecrire la fonction imprimerAnagrammes qui prend en argument un mot 
et un dic--
tionnaire et qui imprime la liste des anagrammes de ce mot composés de mots du 
dictionnaire.
Estimer la complexité de cette fonction.

(* Caml *) {Pascal}
imprimerAnagrammes : procedure imprimerAnagrammes (d:dictXXX;
dictXXX --> mot --> unit u:mot);
* >|<