X/ENS Informatique B MP-PC 2016

Thème de l'épreuve Structure union-find et coupure minimale
Principaux outils utilisés programmation impérative
Mots clefs Réseaux, classes d'équivalence

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 -- ECOLES NORMALES SUPERIEURES
ECOLE SUPERIEURE DE PHYSIQUE ET DE CHIMIE INDUSTRIELLES

CONCOURS D'ADMISSION 2016

FILIERES

MP HORS SPECIALITE INFO
FILIERES PC

COMPOSITION D'INFORMATIQUE ­ B ­ (XELCR)
(Duree : 2 heures)
L'utilisation des calculatrices n'est pas autorisee pour cette epreuve.
Le langage de programmation sera obligatoirement Python.

Ce sujet est decoupe en deux parties totalement independantes toutes deux 
portant sur
l'etude de reseaux sociaux : la premiere porte sur de la programmation en 
Python ; la seconde
porte sur l'interrogation de base de donnees a l'aide de requetes en SQL.

A - Programmation en Python
Notations.

On designera par [[n]] l'ensemble des entiers de 0 a n - 1 : [[n]] = {0, . . . 
, n - 1}.

Objectif. Le but de cette partie est de regrouper des personnes par affinite 
dans un reseau
social. Pour cela, on cherche a repartir les personnes en deux groupes de sorte 
a minimiser le
nombre de liens d'amitie entre les deux groupes. Une telle partition s'appelle 
une coupe minimale
du reseau.

Complexite. La complexite, ou le temps d'execution, d'un programme P (fonction 
ou
procedure) est le nombre d'operations elementaires (addition, multiplication, 
affectation, test,
etc...) necessaires a l'execution de P . Lorsque cette complexite depend de 
plusieurs parametres
n et m, on dira que P a une complexite en O((n, m)), lorsqu'il existe trois 
constantes A, n0
et m0 telles que la complexite de P soit inferieure ou egale a A × (n, m), pour 
tout n > n0 et
m > m0 .
1

Lorsqu'il est demande de donner une certaine complexite, le candidat devra 
justifier cette
derniere si elle ne se deduit pas directement de la lecture du code.

Implementation.

Dans ce sujet, nous adopterons la syntaxe du langage Python.

On rappelle qu'en Python, on dispose des operations suivantes, qui ont toutes 
une complexite
constante (car en Python, les listes sont en fait des tableaux de taille 
dynamique) :
· [] cree une liste vide (c.-a-d. ne contenant aucun element)
· [x]*n qui cree une liste (ou un tableau) a n elements contenant tous la 
valeur contenue
dans x. Par exemple, [1]*3 renvoie le tableau (ou la liste) [1,1,1] a 3 cases 
contenant
toutes la meme valeur 1.
· len(liste) renvoie la longueur de la liste liste
· liste[i] designe le (i + 1)-eme element de la liste liste s'il existe et 
produit une erreur
sinon (noter que le premier element de la liste est liste[0]).
· liste.append(x) ajoute le contenu de x a la fin de la liste liste qui 
s'allonge ainsi
d'un element. Par exemple, apres l'execution de la suite d'instructions " liste 
= [];
liste.append(2); liste.append([1,3]);", la variable liste a pour valeur la liste
[2, [1, 3]]. Si ensuite on fait l'instruction liste[1].append([7,5]);, la 
variable
liste a pour valeur la liste [2, [1, 3, [7,5]]].
· liste.pop() renvoie la valeur du dernier element de la liste liste et 
l'elimine de
la liste. Ainsi, apres l'execution de la suite d'instructions " listeA = 
[1,[2,3]];
listeB = listeA.pop(); c = listeB.pop(); ", les trois variables listeA, listeB 
et
c ont pour valeurs respectives [1], [2] et 3.
· random.randint(a,b) renvoie un entier tire (pseudo)aleatoirement et 
uniformement
dans l'ensemble {a, a + 1, . . . , b - 1, b}.
· True et False sont les deux valeurs booleennes Vrai et Faux.
Important : L'usage de toute autre fonction sur les listes telle que 
liste.insert(i,x),
liste.remove(x), liste.index(x), ou encore liste.sort(x) est rigoureusement 
interdit
(ces fonctions devront etre programmees explicitement si necessaire).
Dans la suite, nous distinguerons fonction et procedure : les fonctions 
renvoient une valeur
(un entier, une liste,...) tandis que les procedures ne renvoient aucune valeur.
Nous attacherons la plus grande importance a la lisibilite du code produit par 
les candidats ;
aussi, nous encourageons les candidats a introduire des procedures ou fonctions 
intermediaires
lorsque cela simplifie l'ecriture.

Partie I. Reseaux sociaux
Structure de donnees. Nous supposerons que les individus sont numerotes de 0 a 
n - 1 ou
n est le nombre total d'individus. Nous representerons chaque lien d'amitie 
entre deux individus
i et j par une liste contenant leurs deux numeros dans un ordre quelconque, 
c.-a-d. par la liste
[i,j] ou par la liste [j,i] indifferemment.

2

Un reseau social R entre n individus sera represente par une liste reseau a 
deux elements
ou :
· reseau[0] = n contient le nombre d'individus appartenant au reseau
· reseau[1] = la liste non-ordonnee (et potentiellement vide) des liens 
d'amitie declares
entre les individus
La figure 1 donne l'exemple d'un reseau social et d'une representation possible 
sous la forme de
liste. Chaque lien d'amitie entre deux personnes est represente par un trait 
entre elles.
0

2

4

6

1

3

5

7

reseau = [ 8,
[ [0,1], [1,3], [3,2], [2,0], [0,3], [2,1], [4,5],
[5,7], [7,6], [6,4], [7,4], [6,5], [2,4], [5,3] ]
]
Figure 1 ­ Un reseau a 8 individus ayant 14 liens d'amitie declares et une de 
ses representations
possibles en memoire sous forme d'une liste [ Nombre d'individus, liste des 
liens d'amitie ].
Question 1. Donner une representation sous forme de listes pour chacun des deux 
reseaux
sociaux ci-dessous :
0

1

2

2
3

0
4

1

4
3

Reseau A

Reseau B

Question 2. Ecrire une fonction creerReseauVide(n) qui cree, initialise et 
renvoie la
representation sous forme de liste du reseau a n individus n'ayant aucun lien 
d'amitie declare
entre eux.
Question 3. Ecrire une fonction estUnLienEntre(paire,i,j) ou paire est une 
liste a deux
elements et i et j sont deux entiers, et qui renvoie True si les deux elements 
contenus dans
paire sont i et j dans un ordre quelconque ; et renvoie False sinon.
Question 4. Ecrire une fonction sontAmis(reseau,i,j) qui renvoie True s'il 
existe un lien
d'amitie entre les individus i et j dans le reseau reseau ; et renvoie False 
sinon.
Quelle est la complexite en temps de votre fonction dans le pire cas en 
fonction du nombre
m de liens d'amitie declares dans le reseau ?
Question 5. Ecrire une procedure declareAmis(reseau,i,j) qui modifie le reseau 
reseau
pour y ajouter le lien d'amitie entre les individus i et j si ce lien n'y 
figure pas deja.

3

Quelle est la complexite en temps de votre procedure dans le pire cas en 
fonction du nombre
m de liens d'amitie declares dans le reseau ?
Question 6. Ecrire une fonction listeDesAmisDe(reseau,i) qui renvoie la liste 
des amis de
i dans le reseau reseau.
Quelle est la complexite en temps de votre fonction dans le pire cas en 
fonction du nombre
m de liens d'amitie declares dans le reseau ?

Partie II. Partitions
Une partition en k groupes d'un ensemble A a n elements consiste en k 
sous-ensembles
disjoints non-vides A1 , . . . , Ak de A dont l'union est A, c.-a-d. tels que 
A1  · · ·  Ak = A
et pour tout i 6= j, Ai  Aj = . Par exemple A1 = {1, 3}, A2 = {0, 4, 5}, A3 = 
{2} est une
partition en trois groupes de A = [[6]]. Dans cette partie, nous implementons 
une structure de
donnees tres efficace pour coder des partitions de [[n]].
Le principe de cette structure de donnees est que les elements de chaque groupe 
sont structures par une relation filiale : chaque element a un (unique) parent 
choisi dans le groupe et
l'unique element du groupe qui est son propre parent est appele le representant 
du groupe. On
s'assure par construction que chaque element i du groupe a bien pour ancetre le 
representant
du groupe, c.-a-d. que le representant du groupe est bien le parent du parent 
du parent etc.
(autant de fois que necessaire) du parent de l'element i. La relation filiale 
est symbolisee par
une fleche allant de l'enfant au parent dans la figure 2 qui presente un 
exemple de cette structure
de donnees. Dans l'exemple de cette figure, 14 a pour parent 11 qui a pour 
parent 1 qui a pour
parent 9 qui est son propre parent. Ainsi, 9 est le representant du groupe 
auquel appartiennent
14, 11, 1 et 9. Notons que ce groupe contient egalement 8, 13 et 15.
A noter que la representation n'est pas unique (si l'on choisit un autre 
representant pour un
groupe et une autre relation filiale, on aura une autre representation du 
groupe).

9
15

3

13

1
8

4
11

10
2

12

5
7

6
0

14

Figure 2 ­ Une representation filiale de la partition suivante de [[16]] en 
quatre groupes :
{1, 8, 9, 11, 13, 14, 15}, {2, 3, 4, 12}, {10} et {0, 5, 6, 7} dont les 
representants respectifs sont 9, 3,
10 et 5.
Pour coder cette structure, on utilise un tableau parent a n elements ou la 
case parent[i]
contient le numero du parent de i. Par exemple, les valeurs du tableau parent 
encodant la
representation filiale donnee dans la figure 2 sont :

4

i:
parent[i] :

0
6

1
9

2
3

3
3

4
3

5
5

6
5

7
5

8
1

9
9

10
10

11
1

12
4

13
9

14
11

15
9

Question 7. Donner les valeurs du tableau parent encodant les representations 
filiales des
deux partitions de [[10]] ci-dessous, et preciser les representants de chaque 
groupe :
5
0

7

4
8

1
6

3

9

2

1

9

8

Representation filiale A

7
4

5

3
0

6

2

Representation filiale B

Initialement, chaque element de [[n]] est son propre representant et la 
partition initiale consiste
en n groupes contenant chacun un individu. Ainsi, initialement, parent[i] = i 
pour tout i  [[n]].
Question 8. Ecrire une fonction creerPartitionEnSingletons(n) qui cree et 
renvoie un
tableau parent a n elements dont les valeurs sont initialisees de sorte a 
encoder la partition de
[[n]] en n groupes d'un seul element.
Nous sommes interesses par deux operations sur les partitions :
· Determiner si deux elements appartiennent au meme groupe dans la partition.
· Fusionner deux groupes pour n'en faire plus qu'un. Par exemple, la fusion des 
groupes
A1 = {1, 3} et A3 = {2} dans la partition de [[6]] donnee en exemple au tout 
debut de
cette partie donnera la partition en deux groupes A2 = {0, 4, 5} et A4 ou A4 = 
A1  A3 =
{1, 2, 3}.
Question 9. Ecrire une fonction representant(parent,i) qui utilise le tableau 
parent pour
trouver et renvoyer l'indice du representant du groupe auquel appartient i dans 
la partition
encodee par le tableau parent.
Quelle est la complexite dans le pire cas de votre fonction en fonction du 
nombre total n
d'elements ? Donnez un exemple de tableau parent a n elements qui atteigne 
cette complexite
dans le pire cas.
Pour realiser la fusion de deux groupes designes par l'un de leurs elements i 
et j respectivement, on applique l'algorithme suivant :
1. Calculer les representants p et q des deux groupes contenant i et j 
respectivement.
2. Faire parent[p] = q.
La figure 3 presente la structure filiale obtenue apres la fusion des groupes 
contenant respectivement 6 et 14 de la figure 2.
Question 10. Ecrire une procedure fusion(parent,i,j) qui modifie le tableau 
parent pour
fusionner les deux groupes contenant i et j respectivement.
5

9
15

3

13

1
8

5
11

7

14

4
6

10
2

12

0

Figure 3 ­ Representation filiale obtenue apres la fusion des groupes contenant 
respectivement
6 et 14 de la figure 2.
Pour l'instant, la structure de donnees n'est pas tres efficace comme le montre 
la question
suivante.
Question 11. Proposer une suite de (n - 1) fusions dont l'execution a partir de 
la partition en
n singletons de [[n]], necessite de l'ordre de n2 operations elementaires.
Pour remedier a cette mauvaise performance, une astuce consiste a compresser la 
relation filiale apres chaque appel a la fonction representant(parent,i). 
L'operation de compression consiste a faire la chose suivante : si p est le 
resultat de l'appel a la fonction
representant(parent,i), modifier le tableau parent de facon a ce que chaque 
ancetre (c.a-d. parent de parent . . . de parent) de i, i y compris, ait pour 
parent direct p. Noter bien
que meme si un appel a representant(parent,i) renvoie le representant de i elle 
modifie
egalement le tableau parent. Si l'on reprend l'exemple de la figure 2, le 
resultat de l'appel
representant(parent,14) est 9, que l'on a calcule en remontant les ancetres 
successifs de 14 :
11, 1 puis 9. L'operation de compression consiste alors a donner la valeur 9 
aux cases d'indices
14, 11, et 1 du tableau parent. La structure filiale obtenue apres l'operation 
de compression
menee depuis 14 est illustree dans la figure 4.

9
15

13

1
8

3
11

14

4
12

10
2

5
7

6
0

Figure 4 ­ Resultat de la compression depuis 14 dans la representation filiale 
de la figure 2.
Question 12. Modifier votre fonction representant(parent,i) pour qu'elle 
modifie le tableau
parent pour faire pointer directement tous les ancetres de i vers le 
representant de i une fois
qu'il a ete trouve.
En quoi cette optimisation de la structure filiale peut-elle etre consideree 
comme "gratuite"
du point de vue de la complexite ?

6

Afin d'afficher de maniere lisible la partition codee par un tableau parent, on 
souhaite
calculer a partir du tableau parent la liste des listes des elements des 
differents groupes. Une
sortie possible pour le tableau parent correspondant a la figure 2 serait :
[ [
[
[
[

15, 8, 1, 9, 11, 13, 14 ],
4, 3, 2, 12 ],
7, 5, 6, 0 ],
10 ] ]

Question 13. Ecrire une fonction listeDesGroupes(parent) qui renvoie la liste 
des differents
groupes codes par le tableau parent sous la forme d'une liste des listes des 
elements des differents
groupes.

Partie III. Algorithme randomise pour la coupe minimum
Revenons a present a notre objectif principal : Trouver une partition des 
individus d'un
reseau social en deux groupes qui minimise le nombre de liens d'amities entre 
les deux groupes.
Pour resoudre ce probleme nous allons utiliser l'algorithme randomise suivant :
Entree : un reseau social a n individus
1. Creer une partition P en n singletons de [[n]]
2. Initialement aucun lien d'amitie n'est marque
3. Tant que la partition P contient au moins trois groupes et qu'il reste des 
liens d'amitie
non-marques dans le reseau faire :
(a) Choisir un lien uniformement au hasard parmi les liens non-marques du 
reseau,
notons-le [i,j].
(b) Si i et j n'appartiennent pas au meme groupe dans la partition P , 
fusionner les deux
groupes correspondants
(c) Marquer le lien [i,j].
4. Si P contient k > 3 groupes, faire k - 1 fusions pour obtenir deux groupes.
5. Renvoyer la partition P .
La figure 5 presente une execution possible de cet algorithme randomise sur le 
reseau de la
figure 1.
Question 14. Ecrire une fonction coupeMinimumRandomisee(reseau) qui renvoie le 
tableau
parent correspondant a la partition calculee par l'algorithme ci-dessus.
Indication. Au lieu de marquer explicitement les liens deja vus, on pourra 
avantageusement les
positionner a la fin de la liste non-ordonnee des liens du reseau et ainsi 
pouvoir tirer simplement
les liens au hasard parmi ceux places au debut de la liste.

7

Étape 0

Étape 1

0

2

4

6

1

3

5

7

1

2

4

6

3

5

7

0

Étape 2
1

2

0
3

Étape 3
6

4

1

2

0

5

7

3

Étape 4
1

2

3

4
7

5

Étape 6
1

2

0

3

6

7

6

7

5

Étape 5
6

0

4

1

2

0

3

4

5

Résultat final

4
6

7

5

1

2

0

3

4
6

7

5

Figure 5 ­ Une execution de l'algorithme randomise sur le reseau de la figure 1 
ou les liens
selectionnes aleatoirement sont dans l'ordre : [2,1], [4,5], [6,5], [0,3], 
[2,0], [3,2] et
[5,7]. Les liens representes en noir epais sont les liens selectionnes au 
hasard a l'etape courante ;
les liens epais et grises sont les liens marques par l'algorithme ; les ronds 
representent la partition
a l'etape courante.

8

Quelle est la complexite de votre procedure en fonction de n, m et (n), ou m 
est le nombre
de liens d'amitie declares dans le reseau et ou (n) designe la complexite d'un 
appel a la fonction
representant ?
Question 15. Ecrire une fonction tailleCoupe(reseau, parent) qui calcule le 
nombre de
liens entre les differents groupes de la partition representee par parent dans 
le reseau reseau.
On peut demontrer que cet algorithme renvoie une coupe de taille minimum avec 
une probabilite superieure a 1/n, ce qui fait que la meilleure parmi n 
executions independantes de cet
algorithme est effectivement minimum avec probabilite superieure a 1/e  
0.36787....
La structure de donnees filiale avec compression pour les partitions est 
particulierement
efficace aussi bien en pratique qu'en theorie. En effet, la complexite de k 
operations est de
O(k(k)) operations elementaires ou (k) est l'inverse de la fonction 
d'Ackermann, une fonction
qui croit extremement lentement vers l'infini (par exemple (1080 ) = 5).

B - Programmation SQL
Une representation simplifiee, reduite a deux tables, de la base de donnees 
d'un reseau social
est donnee dans la figure 6.
LIENS

INDIVIDUS
id
1
2
..
.

nom
Potter
Granger
..
.

prenom
Harry
Hermione
..
.

id1
1
2
..
.

id2
2
1
..
.

Figure 6 ­ Schema de la base de donnees du reseau social
La table INDIVIDUS repertorie les individus et contient les colonnes
· id (cle primaire), un entier identifiant chaque individu ;
· nom, une chaine de caracteres donnant le nom de famille de l'individu ;
· prenom, une chaine de caracteres donnant le prenom de l'individu.
La table LIENS repertorie les liens d'amities entre individus et contient les 
colonnes
· id1, entier identifiant le premier individu du lien d'amitie ;
· id2, entier identifiant le second individu du lien d'amitie.

9

On supposera par ailleurs que pour tout couple (x,y) dans la table LIENS, le 
couple (y,x) est
egalement present dans la table (contrairement a la partie precedente de cet 
enonce).
Question 16. Ecrire une requete SQL qui renvoie les identifiants des amis de 
l'individu d'identifiant x.
Question 17. Ecrire une requete SQL qui renvoie les (noms,prenoms) des amis de 
l'individu
d'identifiant x.
Question 18. Ecrire une requete SQL qui renvoie les identifiants des individus 
qui sont amis
avec au moins un ami de l'individu d'identifiant x.

10