Adloun

É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.

Motnaïfdistinctsélagué
`AAB`633
`AABB`2466
`AAABBB`7202020
`BANANE`720180180

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.