X Informatique MP/PC 2012

Thème de l'épreuve Le problème du « sandwich au jambon », ou théorème de Stone-Tukey
Principaux outils utilisés tableaux
Mots clefs sandwich au jambon, théorème de Stone-Tukey, hyperplan, partition

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 1 € ⬅ clique ici
👈 gratuite pour tous les corrigés si tu crées un compte
- - - - - -
👈 gratuite pour ce corrigé 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


ECOLE POLYTECHNIQUE ­ ECOLE NORMALE SUPERIEURE DE CACHAN
ECOLE SUPERIEURE DE PHYSIQUE ET DE CHIMIE INDUSTRIELLES

CONCOURS D'ADMISSION 2012

FILIERE

MP HORS SPECIALITE INFO
FILIERE PC

COMPOSITION D'INFORMATIQUE ­ B ­ (XEC)
(Duree : 2 heures)
L'utilisation des calculatrices n'est pas autorisee pour cette epreuve.
Le langage de programmation choisi par le candidat doit etre specifie en tete 
de la copie.

Sandwich au jambon
Le probleme dit du sandwich au jambon ou bien encore appele theoreme de 
Stone-Tukey
s'enonce de la maniere suivante : un ensemble de n points en dimension d peut 
toujours etre
separe en deux parties de cardinal au plus n/2 par un hyperplan de dimension d 
- 1 (certains
points peuvent etre dans l'hyperplan), ou n/2 designe la partie entiere de n/2. 
De maniere
concrete, un ensemble de points dans l'espace peut etre separe en deux parties 
quasi-egales par
un plan. De meme un ensemble de points dans le plan peut etre separe en deux 
par une droite et
meme en 4 a l'aide de deux droites. Ce sujet porte sur la resolution 
algorithmique de ce probleme
et de problemes connexes selon differentes methodes.
Dans tout le probleme, les tableaux sont indices a partir de 1. L'acces a la 
i-eme case d'un
tableau tab est note tab[i]. Quel que soit le langage utilise, on suppose que 
les tableaux peuvent
etre passes comme arguments des fonctions. En outre, il existe une primitive 
allouer(m, c) pour
creer un tableau de taille m dont chaque case contient c a l'origine, ainsi 
qu'une primitive taille(t)
qui renvoie la taille d'un tableau t. Enfin, on disposera d'une fonction 
floor(x) qui renvoie la
partie entiere x pour tout reel x  0.
La complexite, ou le temps d'execution, d'un programme P (fonction ou 
procedure) est le
nombre d'operations elementaires (addition, soustraction, multiplication, 
division, affectation,
etc...) necessaires a l'execution de P . Lorsque cette complexite depend d'un 
parametre n, on
dira que P a une complexite en O(f (n)), s'il existe K > 0 tel que la 
complexite de P est au
plus Kf (n), pour tout n. Lorsqu'il est demande de garantir une certaine 
complexite, le candidat
devra justifier cette derniere si elle ne se deduit pas directement de la 
lecture du code.

1

Partie I. Grand, petit et median
Dans cette partie, nous supposerons donne un tableau tab contenant n nombres 
reels. Les
indices du tableau vont de 1 a n. Nous denoterons par tab[a..b] le tableau pris 
entre les indices a
et b c'est-a-dire les cellules tab[a], tab[a + 1], . . . , tab[b - 1], tab[b]. 
Nous supposerons dans l'enonce
que a  b.
Nous utiliserons le tableau de taille 11 suivant pour nos exemples :
3

2

5

8

1

34

21

6

9

14

8

Question 1 Ecrire une fonction calculeIndiceMaximum(tab, a, b) qui renvoie 
l'indice d'une
case ou se trouve le plus grand reel de tab[a..b]. Sur le tableau precedent 
avec a = 1 et b = 11,
la fonction renverra 6 car la case 6 contient la valeur 34.
Question 2 Ecrire une fonction nombrePlusPetit(tab, a, b, val) qui renvoie le 
nombre
d'elements dans le tableau tab[a..b] dont la valeur est plus petite ou egale a 
val. Sur le
tableau exemple, pour une valeur de val egale a 5, et a = 1, b = 11, la 
fonction devra renvoyer
la valeur 4 car seuls les nombres 3, 2, 5, 1 sont inferieurs ou egaux a 5.
Nous allons maintenant calculer un median d'un tableau. Rappelons qu'une valeur 
mediane
m d'un ensemble E de nombres est un element de E tel que les deux ensembles Em (les nombres de E 
strictement plus grands
que m) verifient |Em |  n/2. Notez que le probleme du median 
est une
reformulation de probleme dit du sandwich au jambon pris en dimension 1. Une 
methode naive
consiste donc a parcourir les elements de l'ensemble et a calculer pour chacun 
d'eux les valeurs
de |Em | mais il est possible de faire mieux comme nous allons le 
voir dans la partie
suivante.

Partie II. Un tri pour accelerer
Une methode plus efficace serait de trier le tableau par ordre croissant tout 
en prenant la
cellule du milieu dans le tableau trie. Cette methode certes rapide requiert 
O(n ln n) operations.
Il existe une methode optimale en temps lineaire O(n) pour trouver le median 
d'un ensemble
de n elements. Cette partie a pour but d'en proposer une implementation.
Une fonction annexe necessaire pour cet algorithme consiste a savoir separer en 
deux un
ensemble de valeurs. Soit un tableau tab et un reel appele pivot p = tab[i], il 
s'agit de reordonner
les elements du tableau en mettant en premier les elements strictement plus 
petits que le pivot
tab

p . Sur le tableau exemple, en prenant comme valeur de pivot 8 on obtiendra le tableau resultat suivant : 3, 2, 5, 1, 6 8, 8 21, 34, 9, 14 Notez que dans le resultat les nombres plus petits que le pivot 3, 2, 5, 1, 6 peuvent etre dans n'importe quel ordre les uns par rapport aux autres. 2 Question 3 Ecrire une fonction partition(tab, a, b, indiceP ivot) qui prend en parametre un tableau d'entiers tab[a..b] ainsi qu'un entier a indiceP ivot b. Soit p = tab[indiceP ivot]. La fonction devra reordonner les elements de tab[a..b] comme explique precedemment en prenant comme pivot le nombre p. La fonction retournera le nouvel indice de la case ou se trouve la valeur p. Dans cette question, on suppose que les modifications effectuees par la fonction sur le tableau tab sont persistantes, meme apres l'appel de la fonction. Remarquons que le n/2-eme element dans l'ordre croissant d'un tableau de taille n est un element median du tableau considere. Nous allons donc non pas programmer une methode pour trouver le median mais plus generalement pour trouver le k-eme element d'un ensemble. Nous allons utiliser l'algorithme suivant : On cherche le k-eme element du tableau tab[a..b]. ­ Si k = 1 et a = b alors renvoyer tab[a] ­ Sinon, soit p = tab[a]. Partitionner le tableau tab[a..b] en utilisant le pivot p en mettant en premier les elements plus petits que p. Soit i l'indice de p dans le tableau resultant. ­ Si i - a + 1 > k chercher le k-eme element dans tab[a..i - 1] et renvoyer cet element. ­ Si i - a + 1 = k renvoyer le pivot. ­ Si i - a + 1 < k chercher le (k - i + a - 1)-eme element dans tab[i + 1..b] et renvoyer cet element. Question 4 Ecrire une fonction elementK(tab, a, b, k) qui realise l'algorithme de selection du k-eme element dans le tableau tab[a..b] decrit precedemment et renvoie cet element. Question 5 Supposons que dans l'algorithme precedent nous voulions rechercher le premier element mais qu'a chaque etape le pivot choisi est le plus grand element, quel est un ordre de grandeur du nombre d'operations realisees par votre fonction ? L'algorithme precedent ne semble donc pas ameliorer le calcul du median. Le probleme vient du fait que le pivot choisi peut etre mauvais c'est-a-dire qu'a chaque etape un seul element du tableau a ete elimine. En fait, si l'on peut choisir un pivot p dans tab[a..b] tel qu'il y ait au moins (b - a)/5 elements plus petits et (b - a)/5 plus grands alors on peut montrer que l'algorithme precedent fonctionne optimalement en temps O(n). Pour choisir un tel element dans tab[a..b], on realise l'algorithme choixPivot suivant ou chaque etape sera illustree en utilisant le tableau donne en introduction en prenant a = 2 et b = 9. ­ On decoupe le tableau en paquets de 5 elements plus eventuellement un paquet plus petit. On calcule l'element median de chaque paquet. xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx 3 2 5 8 1 34 21 6 9 xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx 14 8 S'il n'y a qu'un paquet on renvoie son median. Sinon on place ces elements medians au debut du tableau. xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx 3 5 9 2 8 1 3 34 21 6 xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxx 14 8 ­ On realise choixPivot sur les medians precedents. Dans notre exemple on recommence donc les etapes precedentes en prenant a = 2 et b = 3. xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx xxxxxxxxx 3 5 9 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 2 8 1 34 21 6 14 8 Question 6 Ecrire la fonction choixPivot(tab, a, b) qui realise l'algorithme precedent et renvoie la valeur du pivot. Partie III. De la 1D vers la 2D, des nombres aux points. Pour un reel x 0, on note dans cette partie x la partie entiere superieure de x, c'esta-dire, le plus petit entier qui est plus grand ou egal a x : x - 1 < x x. On supposera disposer d'une fonction ceil(x) qui renvoie la partie entiere superieure x pour tout reel x 0. Dans la partie precedente, nous avons etudie le probleme du median en dimension 1. On supposera donc que vous disposez maintenant d'une fonction indiceMedian(tab, a, b) qui calcule un element median du tableau tab[a..b] et renvoie l'indice de cet element. Vous supposerez de plus que cette fonction ne modifie pas l'ordre des elements du tableau tab. Dans cette partie, nous generalisons l'algorithme de maniere a trouver deux droites dans le plan separant un ensemble de n points en 4 parties de cardinal plus petit que n/4, Soit E un ensemble de n points tel qu'il n'existe pas trois points alignes. Nous allons chercher deux lignes L= et L/ separant cet ensemble de points en 4 parties comme le montre la troisieme figure ci-dessous. En effet, dans cette figure chaque partie est composee d'exactement 2 points, les points situes sur les lignes n'etant pas pris en compte. Nous supposerons donnes dans cette partie deux tableaux tabX et tabY de taille n contenant les coordonnees des n points. Ainsi le point i a comme abscisse tabX[i] et comme ordonnee tabY [i]. L= L= L/ La premiere etape est de separer les points en deux ensembles de meme cardinal. Il suffit de remarquer que l'on peut toujours effectuer cette separation par une ligne horizontale notee L= passant par un point d'ordonnee mediane comme le montre le second schema ci-dessus. Question 7 Ecrire une fonction coupeY(tabX, tabY ) qui renvoie l'ordonnee d'une ligne horizontale separant les points en deux parties de cardinal au plus n/2. 4 La seconde ligne L/ est plus difficile a trouver. Nous allons en realite trouver le point d'intersection des deux lignes L= et L/ . Soit P un point sur la droite horizontale L= precedente de coordonnees (x, y). On veut verifier si ce point peut etre le point d'intersection des deux lignes L= et L/ . Nous allons trouver dans un premier temps l'angle entre L= et L/ en utilisant le fait que L/ doit separer en deux parties de cardinal proche les points au dessus de L= . Ensuite nous allons verifier si la droite L/ ainsi devinee separe les points en dessous de L= en deux parties presque egales. L/ ? L= P Concretement on considere les demi-droites partant de P = (x, y) et joignant les k points de E au dessus strictement de L= comme indique sur le schema ci-dessus. On calcule ensuite les angles entre L= et ces demi-droites. Remarquez alors que toute demi-droite d'angle median partage en deux parties de cardinal k/2 les points au dessus de L= . Nous supposerons donnee une fonction angle(x, y, x2, y2) qui calcule et renvoie l'angle forme par une demi-droite horizontale partant de (x, y) et allant vers la droite et le segment (x, y) - (x2, y2). La valeur retournee sera comprise dans l'intervalle [0, 2[. Question 8 Ecrire une fonction demiDroiteMedianeSup(tabX, tabY, x, y) qui calcule et renvoie un angle median entre L= et les segments reliant P = (x, y) avec les points de E dont l'ordonnee est superieure a y. Pour un point P donne, nous avons determine l'angle que doit prendre L/ pour couper les points au dessus de L= en 2 parties de taille au plus moitie. Il faut maintenant verifier que cette droite L/ coupe aussi les points en dessous de L= en 2 parties quasi-egales. Il suffit de verifier que l'angle de L/ partitionne les angles formes entre P et les points en dessous de L= en deux parties de cardinal /2. Question 9 Ecrire une fonction verifieAngleSecondeDroite(tabX, tabY, x, y, theta) qui calcule les angles formes entre L= et les points strictement au dessous de L= . Votre fonction devra renvoyer : 0 si theta est une mediane des angles. -1 si le nombre d'angles strictement plus petits que theta est > /2 1 si le nombre d'angles strictement plus grands que theta est > /2 Si xmin est l'abscisse minimale des points de E et xmax l'abscisse maximale, alors il est evident que l'intersection entre L= et L/ ait une abscisse entre xmin et xmax. Nous allons donc rechercher cette abscisse en utilisant l'algorithme suivant : 5 1. 2. 3. 4. 5. Trouver L= d'ordonnee y. Soit = xmin et = xmax. On calcule P le point au milieu de (, y) et (, y). On calcule l'angle possible de la droite L/ par la fonction demiDroiteMedianeSup. Soit d la valeur donnee par la fonction verif ieAngleSecondeDroite avec l'angle trouve precedemment. Si d = 0 alors on a trouve L/ . Si d = -1 on recommence a partir du point 3 en prenant l'abscisse de P a la place de . Si d = 1 on recommence mais en prenant l'abscisse de P a la place de . Question 10 Ecrire la fonction secondeMediane(tabX, tabY, y) qui a partir d'un ensemble E de points donnes par leurs coordonnees et de l'ordonnee de la droite L= calcule et renvoie un tableau contenant dans la premiere case l'abscisse x du point d'intersection de L= et de L/ ainsi que l'angle de L/ dans la seconde case. 6