Vous êtes sur la page 1sur 3

ITC DM 5 MPSI ITC DM 5 MPSI

3. Écrire une fonction egal qui prend en entrée deux chaînes de caractères quelconques s1 et s2,
DM 5 : énoncé qui renvoie True si les deux chaînes de caractères sont égales et False sinon. Bien sûr, on
pourrait écrire la fonction de la manière suivante, mais on se l’interdit ici :

Cette fonction sera considérée fausse :


Problème 1 (sur papier) : Code de Gray def egal (s1 , s2):
Soient s, s1 et s2 des chaînes de caractères et n un entier. On rappelle que : return s1 == s2
- len(s) est le nombre de caractères dans s.
- s[i] est le caractère d’indice i dans s. et toute réponse dans le même esprit que l’implémentation ci-dessus ne rapportera pas de
- s[i:j] est la chaîne de caractères contenant les caractères s[i], s[i+1], . . . , s[j-1]. point !
- s1 + s2 est la concaténation de s1 et de s2.
- s1 * n vaut s1 dupliqué n fois. 4. À l’aide de la fonction egal, écrire une fonction indice qui prend en entrée une liste L ainsi
- Une chaîne de caractères ne peut pas être modifiée. qu’une chaîne de caractères s et qui renvoie l’indice i tel que L[i] vaut s. Si s n’apparaît pas dans
En particulier, les syntaxes suivantes ne fonctionnent pas : L, votre fonction renverra None.
s.append(...)
s[0] = ... 5. En déduire une fonction gray_to_int qui prend en entrée la liste Ln ainsi qu’une chaîne de
caractères
0,1  0,1
s  Gn, et qui renvoie l’entier i dont le code de Gray est s.
Dans tout l’exercice, on parlera de “flipper un bit” lorsqu’on applique la fonction : 0  1
1  0 Nous allons maintenant nous intéresser à quatre méthodes permettant de générer la liste Ln.

Préliminaires Le code de Gray permet d’encoder les entiers positifs avec des suites de bits. Méthode 1 La première méthode consiste à construire le code de Gray sur (n+1) bits à partir du code
Par exemple, le code de Gray sur 3 bits encode les entiers de l’intervalle [|0, 7|] de la manière suivante: de Gray sur n bits :
- Pour n = 1. On pose L1 = ["0", "1"].
Nombre 0 1 2 3 4 5 6 7 - Pour n > 1.
Code de Gray "000" "001" "011" "010" "110" "111" "101" "100" On définit R une copie de la liste Ln–1 et S une copie de la liste Ln–1 écrite à l’envers.
On ajoute ensuite des 0 à gauche de tous les éléments de R et des 1 à gauche de tous les
éléments de S. La liste Ln est alors la concaténation de R et de S.
L’intérêt de ce code par rapport à l’écriture en base 2 habituelle est que pour tout i, les encodages de
i et de (i+1) ne diffèrent que d’un seul bit. Par exemple :
- Pour n = 1. La liste L1 vaut ["0", "1"].
À partir de maintenant, on fixe un entier n  ℕ* et on s’intéresse au code de Gray sur n bits. - Pour n = 2. On a R = ["00", "01"] et S = ["11", "10"] donc : L2 = ["00", "01", "11", "10"].
En Python, l’encodage d’un entier sera un élément de Gn où Gn est l’ensemble des chaînes de - Pour n = 3. On a R = ["000", "001", "011", "010"] et S = ["110", "111", "101", "100"].
caractères de taille n composées de 0 et de 1. Ainsi : Donc : L3 = ["000", "001", "011", "010", "110", "111", "101", "100"].

G3 = {"000", "001", "010", "011", "100", "101", "110", "111"}. 6. Soit n  ℕ*.
Écrire une fonction code_suivant qui prend en entrée la liste Ln et qui renvoie la liste Ln+1.
1. Déterminer le cardinal de Gn. Pour la construction des listes R et S, utilisez une ou des boucles for.

Dans un premier temps, on suppose qu’on dispose d’une liste Ln de taille 2n telle que pour tout 7. Écrire une fonction get_gray1 qui prend en entrée un entier n  ℕ* et qui renvoie la liste Ln à
i  [|0, 2n –1|], la chaîne de caractères Ln[i] est de taille n et contient le code de Gray sur n bits associé l’aide de la méthode 1.
à l’entier i.
Par exemple, pour n = 3, la liste L3 vaut : Méthode 2 La deuxième méthode consiste à construire l’encodage de (i+1) à partir des encodages de
0,…,i.
L3 = ["000", "001", "011", "010", "110", "111", "101", "100"]. L’idée est de partir de l’encodage de i et de flipper le bit le plus à droite possible qui donne une chaîne
de caractères non utilisée pour coder l’un des entiers de [|0, i|].
2. Écrire une fonction int_to_gray qui prend en entrée la liste Ln ainsi qu’un entier i  [|0, 2n –1|],
et qui renvoie le code de Gray sur n bits de i. Par exemple avec n = 3 :
 Le code de 0 est par convention "000".
Nous souhaitons maintenant faire l’opération inverse : étant donnée une chaîne de caractères s  Gn,  Pour obtenir le code de 1 à partir de "000" :
nous allons déterminer l’entier dont le code de Gray est s. - On flippe le bit le plus à droite. On obtient la chaîne de caractères "001" qui n’encode pas
0. On décide donc que 1 est encodé par "001".
 Pour obtenir le code de 2 à partir de "001" :

P. CHATEL 1 sur 5 2022-11-08 P. CHATEL 2 sur 5 2022-11-08


ITC DM 5 MPSI ITC DM 5 MPSI

- On flippe le bit le plus à droite. On obtient "000" qui est déjà utilisé pour encoder 0.
- On flippe le 2ème bit le plus à droite. On obtient "011" qui n’encode ni 0, ni 1. On décide 13. Comment trouver l’écriture binaire de i/2 à partir de l’écriture binaire de i ?
donc que 2 est encodé par "011". On attend la procédure la plus efficace possible.
 Pour obtenir le code de 3 à partir de "011" :
- On flippe le bit le plus à droite. On obtient "010" qui n’encode ni 0, ni 1, ni 2. On décide 14. Écrire une fonction récursive int_to_bin qui prend en entrée deux entiers i, n  ℕ et qui renvoie
donc que 3 est encodé par "010". la chaîne de caractères s contenant la représentation en base 2 de i sur n bits.
 Pour obtenir le code de 4 à partir de "010" : Par exemple : int_to_bin(0,2) vaut "00", int_to_bin(5,4) vaut "0101", int_to_bin(11,4) vaut
- On flippe le bit le plus à droite. On obtient "011" qui est déjà utilisé pour encoder 2. "1011".
- On flippe le 2ème bit le plus à droite. On obtient "000" qui est déjà utilisé pour encoder 0.
- On flippe le 3ème bit le plus à droite. On obtient "110" qui n’encode ni 0, ni 1, ni 2, ni 3. On 15. Écrire une fonction get_gray4 qui prend en entrée un entier n et qui renvoie la liste Ln à l’aide
décide donc que 4 est encodé par "110". de la méthode 4.
 On continue ainsi jusqu’à ce que tous les nombres de [|0, 2n – 1|] soient associés à un code.

8. Écrire une fonction flip qui prend en entrée une chaîne de caractères s  Gn ainsi qu’un entier Problème 2 (sur machine) : Le problème des n dames
j  [|0, n–1|] et qui renvoie une copie de s où s[j] a été flippé.
Le problème des n dames consiste à placer n dames sur un échiquier de taille nn sans qu’aucune
dame n’en menace une autre. En d’autres termes, dans une solution au problème des n dames, deux
9. Écrire une fonction get_gray2 qui prend en entrée l’entier n et qui renvoie la liste Ln générée
dames ne peuvent pas se trouver sur une même ligne, sur une même colonne ou bien sur une même
avec la méthode 2.
diagonale.
Il est souhaitable d’écrire une ou plusieurs fonctions intermédiaires …
Par exemple, la grille de gauche est une solution au problème des 8 dames mais pas la grille de droite
Méthode 3 Dans la méthode 3, on construit l’encodage de (i + 1) directement à partir de la chaîne de car certaines dames sont sur une même diagonale.
caractères s qui encode i. On a deux cas :
- Si le nombre de 1 dans s est pair, on flippe le bit le plus à droite de s.
- Sinon, on flippe le bit situé à gauche du 1 le plus à droite.
Dans les deux cas, la chaîne de caractères obtenue après le flip encode (i+1).

10. Écrire une fonction get_gray3 qui prend en entrée un entier n et qui renvoie la liste Ln à l’aide
de la méthode 3.
Là encore, il est souhaitable d’écrire plusieurs fonctions intermédiaires …

Méthode 4 La dernière méthode consiste à utiliser l’écriture en base 2 de i ainsi qu’une opération
appelée le “ou-exclusif” noté  et défini par :
0  0 = 0, 0  1 = 1, 1  0 = 1, 1  1 = 0. Écrire une fonction get_nb_solutions qui prend en entrée l’entier n et renvoie le nombre de solutions
au problème des n dames. Pour n variant de 1 à 12, vous devez obtenir 1, 0, 0, 2, 10, 4, 40, 92, 352,
11. Écrire une fonction ou_exclusif qui prend en entrée deux chaines de caractères b1 724, 2680 et 14200. Si vous n’y parvenez pas, lisez l’aide ci-dessous.
et b2  {'0','1'} et qui renvoie b1  b2.
Par exemple : ou_exclusif ('0','1') vaut '1', ou_exclusif ('1','1') vaut '0'. Un peu/beaucoup d’aide

Étant données deux chaînes de caractères s1, s2  Gn, le “ou-exclusif bit-à-bit” de s1 et s2 est la chaîne Dans un premier temps, nous allons trouver une solution au problème. On place une dame sur la
de caractères s  Gn telle que : première colonne puis une dame sur la deuxième colonne et ainsi de suite jusqu’à ce que toutes les
s[i] = s1[i]  s2[i] pour tout i  [|0, n – 1|]. dames soient placées et sans qu’aucune ne soit menacée. De plus, nous allons utiliser la technique dite
de backtracking dont le principe est décrit ci-après.
12. Écrire une fonction ou_exclusif_bit_a_bit qui prend en entrée deux chaines de caractères s1 et
s2 et qui renvoie s1  s2. Dans ce qui suit, la variable i est utilisée pour numéroter les lignes (i = 0 correspond à la ligne du haut
Par exemple : ou_exclusif_bit_a_bit('011','110') vaut "101". et i = n-1 correspond à la ligne du bas) et la variable j est utilisée pour numéroter les colonnes (j = 0
correspond à la colonne de gauche et j = n - 1 correspond à la colonne de droite). De plus, on parlera
de “la dame numéro j” pour faire référence à la dame que l’on souhaite placer sur la jème colonne.
Soit n  ℕ* et i  [|0, 2n – 1|].
On note s1  Gn la chaîne de caractères contenant l’écriture binaire de i et s2  Gn la chaîne de Afin de placer la dame numéro j, on suppose que les dames sur les j premières colonnes ont déjà été
caractères contenant l’écriture binaire de i/2 . Alors le code de Gray de i est le ou-exclusif bit-à-bit placées et qu’elles ne se menacent pas mutuellement. Alors :
de s1 et de s2.  On calcule l’ensemble des lignes que la dame numéro j peut occuper sans être menacée.
 On choisit la première ligne disponible (que l’on notera i dans la suite), on place la dame numéro j
Par exemple, pour n = 3 et i = 6 : s1 = "110" et s2 = "011" donc le code de Gray sur 3 bits de 6 est "101". sur la ligne i puis on essaye de placer les dames des colonnes suivantes. On a alors deux cas :

P. CHATEL 3 sur 5 2022-11-08 P. CHATEL 4 sur 5 2022-11-08


ITC DM 5 MPSI

- Si les autres dames peuvent être placées sans créer de menace, on a trouvé une solution
au problème.
- Sinon, on en déduit que la dame numéro j ne peut pas être placée sur la ligne i et on
réessaye avec une autre ligne.
Les positions des dames déjà placées seront représentées par une liste pos_dames de taille n telle que
pos_dames[j] est la ligne occupée par la dame qui se trouve sur la jème colonne.
Par exemple, les deux configurations données ci-dessus sont représentées par les listes
[6,4,2,0,5,7,1,3] et [0,2,6,4,5,7,3,1].
Lorsque la dame numéro j n’est pas encore placée, la valeur de pos_dames[j] sera arbitraire (None par
exemple).
1. Quelles sont les conditions sur i1, i2, j1, j2  [|0, n – 1|] pour qu’une dame en position (i1, j1)
soit menacée par une dame en position (i2, j2) ?
2. Écrire une fonction dames_se_menacent qui prend en entrée 4 entiers i1, i2, j1, j2 , et qui
renvoie True si les dames en position (i1, j1) et (i2, j2) se menacent, et False dans le cas contraire.
Dans un premier temps, on fixe un entier j  [|0, n – 1|], on suppose que les j premières dames ont
été placées et on essaye de trouver une case non menacée sur la colonne j.
3. Écrire une fonction get_lignes_non_menacees qui prend en entrée la liste pos_dames ainsi
qu’un entier j, et qui renvoie la liste des lignes i telles que les dames des j premières colonnes
ne menacent pas la case (i,j).
Par exemple,
get_lignes_non_menacees([6,4,None,None,None,None,None,None], 2) renvoie [0, 1, 2, 7],
get_lignes_non_menacees([6,4,2,0,5,None,None,None], 5) renvoie [3, 7].
4. Écrire une fonction get_solution qui prend en entrée l’entier n et qui renvoie la liste pos_dames
qui représente une solution au problème des n dames. Votre fonction renverra la liste vide
dans le cas où il n’y a pas de solution. Si vous n’y parvenez pas, vous pouvez lire l’aide ci-
dessous.
Pour écrire la fonction get_solution, on va utiliser une liste de listes lignes_possibles telle que
lignes_possibles[j] contient la liste des lignes non menacées sur lesquels on n’a pas encore
essayé de placer la dame numéro j. On procède de la manière suivante :
- On initialise une variable j à 0.
- On initialise la liste de listes lignes_possibles comme suit :
o La liste lignes_possibles[0] contient tous les éléments de [|0, n – 1|].
o Les autres éléments de lignes_possibles sont initialisés à la liste vide.
- On répète alors les étapes suivantes :
o Si la liste lignes_possibles[j] n’est pas vide alors :
 On supprime - grâce à la méthode pop - le premier élément de la liste
lignes_possibles[j], élément qui sera noté i dans la suite.
 On place la dame numéro j en position i.
 On donne une valeur à lignes_possibles[j+1] à l’aide la fonction de la question 3.
 On incrémente la variable j .
o Sinon, la liste lignes_possibles[j] est vide, on ne peut donc pas placer la dame numéro
j. Dans ce cas, on décrémente j de 1 (backtracking) afin de modifier la position de la
dame numéro j-1.
5. Modifier la fonction de la question 4 pour obtenir une fonction get_solutions qui renvoie la
liste des solutions au problème des n dames.

P. CHATEL 5 sur 5 2022-11-08

Vous aimerez peut-être aussi