Probleme – Les mots bien parenthésés, et pourquoi ils sont si peu nombreux
Exercice · niveau 3 (difficile) · informatique (MP2I/MPI), chapitre 14 — Exploration exhaustive et retour sur trace
Énoncé
Un mot de Dyck de longueur est un mot sur où chaque préfixe compte au moins autant d'ouvrantes que de fermantes, et où le total s'équilibre.
- Les énumérer par force brute, puis par retour sur trace.
- Prouver que le test d'acceptabilité employé est correct — c'est-à-dire qu'il n'élague aucune solution.
- Comparer les deux comptages de nœuds, et identifier la suite obtenue.
Corrigé
1. Les deux versions.
(* FORCE BRUTE : on écrit les 2^(2n) mots, et l'on teste à la fin.
Renvoie le nombre de mots de Dyck. Précondition : n >= 0. *)
let dyck_brute n =
let mot = Bytes.create (2 * n) and bons = ref 0 in
let est_bon () =
let s = ref 0 and ok = ref true in
Bytes.iter (fun c ->
s := !s + (if c = '(' then 1 else -1); if !s < 0 then ok := false) mot;
!ok && !s = 0 in
let rec brute k =
if k = 2*n then (if est_bon () then incr bons)
else begin
Bytes.set mot k '('; brute (k + 1);
Bytes.set mot k ')'; brute (k + 1) end
in brute 0; !bons
(* RETOUR SUR TRACE : on refuse d'écrire ce qui est déjà perdu.
ouvertes = nombre d'ouvrantes posées ; k - ouvertes = nombre de fermantes. *)
let dyck n traiter =
let mot = Bytes.create (2 * n) in
let rec explorer k ouvertes =
if k = 2*n then traiter (Bytes.to_string mot)
else begin
if ouvertes < n then begin (* reste-t-il des ouvrantes ? *)
Bytes.set mot k '('; explorer (k + 1) (ouvertes + 1) end;
if k - ouvertes < ouvertes then begin (* y a-t-il de quoi fermer ? *)
Bytes.set mot k ')'; explorer (k + 1) ouvertes end
end
in explorer 0 0
2. La preuve que l'élagage ne perd rien. Un mot de Dyck vérifie, en tout préfixe, et . Ces deux conditions sont exactement les deux tests. Il faut voir qu'elles sont héréditaires : si un préfixe les viole, aucun prolongement ne peut être un mot de Dyck, puisque les compteurs ne décroissent jamais. Élaguer sur une condition héréditaire ne supprime que des branches sans solution. Réciproquement, tout mot de Dyck a tous ses préfixes conformes, donc survit à l'élagage. Les deux versions énumèrent le même ensemble.
C'est le critère général : un test d'acceptabilité est correct s'il est nécessaire pour toute solution complète et héréditaire le long des branches. Un test seulement nécessaire à la fin — comme est_bon — n'élague rien.
3. La mesure.
| mots de Dyck | nœuds élagués | nœuds bruts | rapport | |
|---|---|---|---|---|
| 1 | 1 | 3 | 7 | 2,3 |
| 2 | 2 | 8 | 31 | 3,9 |
| 3 | 5 | 22 | 127 | 5,8 |
| 4 | 14 | 64 | 511 | 8,0 |
| 5 | 42 | 196 | 10,4 | |
| 6 | 132 | 625 | 13,1 | |
| 7 | 429 | 15,9 | ||
| 8 | 18,9 |
Pour , les cinq mots sont ((())) (()()) (())() ()(()) ()()().
La colonne des solutions est la suite : ce sont les nombres de Catalan, . Ils ont été retrouvés indépendamment par la récurrence , qui traduit la décomposition d'un mot de Dyck en .
Ce que ce problème illustre. : les mots de Dyck sont exponentiellement nombreux, mais exponentiellement moins que les mots quelconques — d'un facteur seulement. C'est pourquoi le rapport de la dernière colonne croît si lentement : l'élagage ne peut pas faire mieux que le rapport entre le nombre de solutions et le nombre de candidats. Ici ce rapport est polynomial, et l'exploration reste exponentielle. Là où l'élagage est spectaculaire — les reines, le sudoku —, c'est que les solutions sont exponentiellement rares.
Ces mêmes mots sont ceux qu'engendre la grammaire du chapitre chap:grammaires, et ce sont eux qu'un analyseur syntaxique reconnaît avec une pile (chapitre chap:sequentielles) — en temps linéaire, sans rien énumérer du tout.
Les autres exercices de ce chapitre Le cours du chapitre
Un blocage sur cet exercice ? Le tuteur d'Adloun guide par questions, sans donner la réponse.