Énumérer les permutations d'un mot à lettres répétées
Exercice · niveau 2 · informatique (MP2I/MPI), chapitre 14 — Exploration exhaustive et retour sur trace
Énoncé
Le retour sur trace naïf sur les permutations de AABB produit résultats, dont seulement sont distincts. Modifier le test d'acceptabilité pour ne produire que les distincts, sans table auxiliaire ni filtrage a posteriori.
Corrigé
On trie d'abord les lettres. Deux lettres égales ne doivent alors être posées que dans l'ordre de leurs indices : on refuse la lettre si sa jumelle est encore libre.
(* Applique traiter à chaque permutation DISTINCTE des lettres de mot.
Précondition : aucune (les lettres sont triées ici même) ; le test d'élagage
ci-dessous serait faux sur des lettres non triées. *)
let permutations_distinctes mot traiter =
let n = String.length mot in
let lettres = Array.init n (fun i -> mot.[i]) in
Array.sort compare lettres; (* le tri EST la précondition *)
let utilise = Array.make n false in
let sortie = Bytes.create n in
let rec explorer k =
if k = n then traiter (Bytes.to_string sortie)
else
for i = 0 to n - 1 do
if not utilise.(i)
(* la jumelle précédente doit avoir DÉJÀ été posée *)
&& not (i > 0 && lettres.(i) = lettres.(i-1) && not utilise.(i-1))
then begin
utilise.(i) <- true; Bytes.set sortie k lettres.(i);
explorer (k + 1);
utilise.(i) <- false
end
done
in explorer 0
Mesuré : le nombre de feuilles atteintes tombe exactement au nombre de mots distincts.
| Mot | naïf | distincts | élagué |
|---|---|---|---|
| `AAB` | 6 | 3 | 3 |
| `AABB` | 24 | 6 | 6 |
| `AAABBB` | 720 | 20 | 20 |
| `BANANE` | 720 | 180 | 180 |
On retrouve bien et .
Pourquoi ce test est correct, et c'est le seul point délicat : parmi les façons d'ordonner lettres identiques, le test n'en accepte qu'une — celle où leurs indices d'origine sont croissants. Il n'en refuse donc aucune classe entière, et n'en accepte aucune deux fois.
Pourquoi on n'utilise pas de table de hachage. Filtrer a posteriori avec une table (chapitre chap:hachage) donnerait le même résultat, mais aurait visité les feuilles de AAABBB pour n'en garder que : on paie l'exploration, puis le stockage. L'élagage, lui, ne descend jamais dans la branche redondante. Filtrer à l'arrivée n'est pas élaguer.
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.