Version interactive avec LaTeX compilé
Option informatique
Arbres couvrants et pavages
Le seul langage de programmation autorisé dans cette épreuve est Caml.
Toutes les fonctions des modules Array et List, ainsi que les fonctions de la bibliothèque standard (celles qui s'écrivent sans nom de module, comme max ou incr ainsi que les opérateurs comme / ou mod) peuvent être librement utilisés.
On utilisera également le générateur pseudo-aléatoire int du module Random. Quand n est un entier supérieur ou égal à 1, l'appel Random. int n renvoie un entier dans l'intervalle (compris entre 0 inclus et n exclu) en simulant une loi uniforme. Les appels successifs à cette fonction fournissent des résultats indépendants.
Les candidats ne devront faire appel à aucun autre module.
En Caml, les tableaux d'objets d'un certain type 'a sont représentés par le type 'a array. L'expression tab. (i) permet d'accéder à l'élément situé en i-ème position du tableau tab. Dans le texte, en dehors du code Caml, cet élément sera noté . Plus généralement, les objets mathématiques seront notés
et représentés en Caml par g, s, adj... sans que cela soit systématiquement explicité.
Toutes les fonctions des modules Array et List, ainsi que les fonctions de la bibliothèque standard (celles qui s'écrivent sans nom de module, comme max ou incr ainsi que les opérateurs comme / ou mod) peuvent être librement utilisés.
On utilisera également le générateur pseudo-aléatoire int du module Random. Quand n est un entier supérieur ou égal à 1, l'appel Random. int n renvoie un entier dans l'intervalle
Les candidats ne devront faire appel à aucun autre module.
En Caml, les tableaux d'objets d'un certain type 'a sont représentés par le type 'a array. L'expression tab. (i) permet d'accéder à l'élément situé en i-ème position du tableau tab. Dans le texte, en dehors du code Caml, cet élément sera noté
Dans ce problème, un graphe
est un couple (
) où :
-
est un ensemble fini dont les éléments sont les sommets de ; -
est la suite des arêtes de , une arête étant une partie de de cardinal 2 . Les sommets et sont appelés les extrémités de l'arête et on dira que a relie et . Si et sont reliés par une arête, on dit qu'ils sont voisins ou adjacents.
Ainsi, les graphes sont non orientés et il n'y a pas d'arête reliant un sommet à lui-même. Par contre, à partir de la partie V, il est possible que plusieurs arêtes aient les mêmes extrémités.
Par convention, nous noterons(respectivement ) le nombre de sommets (respectivement d'arêtes) du graphe et nous supposerons que .
Un graphe sera représenté par le type
type graphe = int list array
Siest un graphe représenté par , alors le nombre de sommets du graphe est donné par la longueur du tableau g. De plus, si , alors g. (s) est une liste contenant les indices des sommets voisins de , dans un ordre quelconque, chaque sommet apparaissant autant de fois qu'il existe d'arêtes vers .
Les complexités temporelles demandées sont des complexités dans le pire des cas et seront exprimées sous la forme
, où
est une fonction la plus simple possible.
Nous utiliserons la représentation graphique habituelle des graphes. Le graphe
, défini par l'instruction
let ;
peut être représenté par le graphique de la figure 1.
let
peut être représenté par le graphique de la figure 1.

Figure 1 Exemple de graphe
Pour
entiers naturels non nuls, nous noterons
le graphe, appelé graphe quadrillage, dont les sommets sont placés sur
colonnes et
lignes, chaque sommet étant relié à ses voisins directs. On convient de numéroter les sommets de gauche à droite et de bas en haut.
Par ailleurs, l'ordre des arêtes ayant une importance en partie V , on convient de numéroter les arêtes en commençant par les arêtes verticales, de bas en haut et de gauche à droite, puis les arêtes horizontales, de gauche à droite et de bas en haut, comme le montre la figure 2 , où
et
. Le rang d'une arête a de
est l'indice
tel que
.
Par ailleurs, l'ordre des arêtes ayant une importance en partie V , on convient de numéroter les

Figure 2 Le graphe
Soit
un graphe.
- Si
, le tableau d'adjacence de est le tableau, dans un ordre quelconque, des voisins de , chaque sommet apparaissant autant de fois qu'il existe d'arêtes vers . On note le tableau de taille tel que, pour tout est le tableau d'adjacence du sommet . Adj est donc représenté par une variable adj de type int array array. - Un chemin dans
est une suite où pour tout compris entre 1 et et sont des sommets voisins. On dira que est un chemin de à de longueur . Par convention, pour sommet de , il existe un chemin de longueur nulle de à . - La composante connexe d'un sommet
de , notée , est l'ensemble des sommets de tels qu'il existe un chemin de à . - On dit que
est connexe si pour tous sommets et de , il existe un chemin de à . - Un cycle dans
est un chemin de longueur d'un sommet à lui-même et dont les arêtes sont deux à deux distinctes. On dit que est acyclique s'il ne contient aucun cycle. - Un arbre est un graphe connexe acyclique.
I Quelques fonctions auxiliaires
Q 1. Écrire une fonction
nombre_aretes : graphe -> int
qui, appliquée à g représentant un graphe , renvoie le cardinal de
.
Q 2. Écrire une commande Caml permettant de créer le tableau des tableaux d'adjacence Adj associé au graphe .
On rappelle que la fonction Array.of_list : 'a list 'a array prend en argument une liste
d'éléments de type 'a et renvoie le tableau
.
Q 3. Écrire une fonction
adjacence : graphe -> int array array
qui, appliquée à g représentant un graphe , renvoie adj représentant le tableau des tableaux d'adjacence Adj associé à
. La fonction adjacence devra être de complexité
et on demande de justifier cette complexité.
Q 4. Écrire une fonction
rang : int * int -> int * int -> int
telle que rang (p,q) (s, t) renvoie le rang de l'arête dans le graphe quadrillage
. Par exemple, rang
renvoie 13 . On suppose que
et
sont adjacents et
et on ne demande pas de le vérifier.
Q 5. Écrire de même sa fonction réciproque
sommets : int * int -> int -> int * int
telle que sommets ( ) i renvoie le couple (
) tel que
et
dans le graphe
.
Q 6. Écrire une fonction
quadrillage : int -> int -> graphe
telle que l'instruction quadrillage p q renvoie le graphe représentant .
nombre_aretes : graphe -> int
qui, appliquée à g représentant un graphe
Q 2. Écrire une commande Caml permettant de créer le tableau des tableaux d'adjacence Adj associé au graphe
On rappelle que la fonction Array.of_list : 'a list
Q 3. Écrire une fonction
adjacence : graphe -> int array array
qui, appliquée à g représentant un graphe
Q 4. Écrire une fonction
rang : int * int -> int * int -> int
telle que rang (p,q) (s, t) renvoie le rang de l'arête
Q 5. Écrire de même sa fonction réciproque
sommets : int * int -> int -> int * int
telle que sommets (
Q 6. Écrire une fonction
quadrillage : int -> int -> graphe
telle que l'instruction quadrillage p q renvoie le graphe représentant
II Caractérisation des arbres
Soit
un graphe à
sommets et
arêtes, représenté par g. Les arêtes de
sont donc numérotées
.
II.A - Propriétés sur les arbres
Q 7. Montrer que les composantes connexes de
forment une partition de
, c'est-à-dire que:
;
-
; - pour tous sommets
et , soit , soit .
Q 8. Montrer que si
et
sont deux sommets de
tels que
, il existe un plus court chemin de
à
et que les sommets d'un plus court chemin sont deux à deux distincts.
Pour désigne le graphe (
) obtenu en ne conservant que les
premières arêtes de
.
Q 9. On suppose que est un arbre. Montrer que pour tout
, les extrémités de
appartiennent à deux composantes connexes différentes de
. En déduire que
.
Q 10. Montrer que les trois propriétés suivantes sont équivalentes:
(i) est un arbre ;
(ii) est connexe et
;
(iii) est acyclique et
.
Pour
Q 9. On suppose que
Q 10. Montrer que les trois propriétés suivantes sont équivalentes:
(i)
(ii)
(iii)
II.B - Manipulation de partitions
Nous souhaitons écrire une fonction qui teste si un graphe est un arbre. Nous allons pour cela utiliser une structure de données permettant de manipuler les partitions de l'ensemble
si
est une partition de
, on choisit dans chaque partie
, un élément particulier
, appelé représentant de
. Notre structure de données doit nous permettre :
- de calculer, pour
, le représentant de la partie contenant ; cet élément sera également appelé représentant de ; - pour deux entiers
et représentant des parties distinctes et , de transformer en réunissant et ou devenant le représentant de la partie .
Nous représenterons une partitionde par une forêt: chaque est représenté par un arbre dont les noeuds sont étiquetés par les éléments de et de racine le représentant de , les arcs étant orientés vers la racine. Nous noterons la hauteur de l'arbre , c'est-à-dire la longueur de sa plus longue branche. Ainsi, est une partition de et peut par exemple être représentée par la forêt de la figure 3.


Figure 3 Une représentation de
Le calcul du représentant d'un entier
se fait donc en remontant jusqu'à la racine de l'arbre (ce qui justifie l'orientation des arcs). Dans l'exemple, les représentants de 2,1 et 7 sont respectivement 0,6 et 7 .
Une partition de
sera représentée par un tableau d'entiers
de taille
de sorte que pour tout
est le père de
si
n'est pas un représentant, et est égal à
si
est un représentant. La partition
peut ainsi être représentée par le tableau
[I -2; 5; 0; 7; 7; 6; -3; -2; 6 I]
Une partition
[I -2; 5; 0; 7; 7; 6; -3; -2; 6 I]
La réunion de deux parties
et
de représentants
et
distincts se fait selon la méthode suivante :
- si
est choisi pour représentant de la partie et devient le père de ; - si
est choisi pour représentant de la partie et devient le père de .
Par exemple, la réunion des parties
et
de la partition
peut donner la nouvelle forêt représentée figure 4.

Figure 4 Une représentation de
Q 11. Écrire une fonction
representant : int array -> int -> int
qui, appliquée à un tableau représentant une partition de
et à
, renvoie le représentant de
.
Q 12. Écrire une fonction
Q 12. Écrire une fonction
union : int array -> int -> int -> unit
qui, appliquée à un tableau représentant une partition de
et à deux représentants
et
distincts, modifie la partition en réunissant les arbres associés à
et
, selon la méthode expliquée ci-dessus, sans oublier, si nécessaire, de modifier
ou
.
On note la partition de
où toutes les parties sont des singletons, c'est-à-dire
.
Q 13. Soit une partition de
construite à partir de
par des réunions successives selon la méthode précédente. Montrer que si
est le représentant d'une partie
, alors le cardinal de
vérifie
.
Q 14. En déduire les complexités des deux fonctions précédentes dans le pire des cas en fonction de pour une partition
construite à partir de
.
Q 15. Écrire une fonction
est_un_arbre : graphe -> bool
qui, appliquée à un graphe g représentant un graphe , renvoie true si
est un arbre et false sinon.
On note
Q 13. Soit
Q 14. En déduire les complexités des deux fonctions précédentes dans le pire des cas en fonction de
Q 15. Écrire une fonction
est_un_arbre : graphe -> bool
qui, appliquée à un graphe g représentant un graphe
III Algorithme de Wilson : arbre couvrant aléatoire
Si
est un graphe connexe et si
, un arbre couvrant de
enraciné en
est un arbre
tel que
et dont
a été choisi pour racine. On convient alors d'orienter les arêtes de l'arbre en direction de la racine
et de représenter
par un tableau parent de taille
, parent. (s) étant égal au père de
dans
si
, et à -1 si
.
La figure 5 représente deux arbres couvrants du graphe , enracinés respectivement en 0 et 2 , et leurs représentations.
La figure 5 représente deux arbres couvrants du graphe

Figure 5 Deux arbres couvrants enracinés de
et leurs représentations
Dans cette partie, nous supposons que
est un graphe connexe, représenté par g, que
est un sommet de
et nous cherchons à construire un arbre couvrant aléatoire de
enraciné en
.
Nous allons pour cela faire évoluer dynamiquement un arbre , représenté par un tableau parent de longueur
vérifiant:
Nous allons pour cela faire évoluer dynamiquement un arbre
- parent. (r) = -1;
- si
n'est pas un sommet de , parent. (s) = -2; - si
est un sommet de autre que la racine, parent. (s) est le père de dans l'arbre .
Nous partons de l'arbre réduit à la racine
, en posant parent.
et parent.
pour tout sommet
. Pour tout sommet
, quand
n'est pas déjà dans l'arbre, on construit un chemin aléatoire
sans boucle qui part de
et qui s'arrête dès qu'il a atteint un sommet de
. La méthode de construction est la suivante:
- au début du calcul,
est réduit à ; - à tout moment,
est de la forme ( ) où les sommets sont deux à deux distincts et les sommets ne sont pas des sommets de ; - tant que l'extrémité
n'est pas un sommet de , on choisit aléatoirement et uniformément un voisin de et on distingue, - si
, on supprime le cycle qui vient d'être formé et devient le nouveau point d'arrivée du chemin ; - sinon,
devient le chemin ; - on renvoie le chemin (
) une fois le calcul terminé.
On représentera un chemin en Caml par le type :
type chemin debut
int; mutable fin : int; suivant : int array}
de telle sorte que si le chemin est représenté par c , alors c .debut est égal à
, c.fin (qui est un champ mutable) est égal à
, et c. suivant est un tableau de taille
tel que pour
, la case d'indice
de c.suivant contient le sommet
. Pour tout autre sommet
, c.suivant. ( t ) pourra prendre une valeur arbitraire.
type chemin
de telle sorte que si le chemin
On rappelle que si c est un objet de type chemin et u un entier représentant un sommet, la modification du champ mutable c.fin pour y mettre u peut se faire avec la commande:
c.fin <- u
c.fin <- u
Q 16. Déterminer, dans le graphe
, le chemin représenté par l'objet
{debut = 1; fin = 4; suivant = [|-5; 2; 5; 3; -1; 4|]}
Q 17. Que peut-on dire de la terminaison de cet algorithme?
Q 18. Écrire une fonction
marche_aleatoire : int array array -> int array -> int -> chemin
telle que l'appel marche_aleatoire adj parent s renvoie l'objet c représentant un chemin de à un sommet
obtenu comme décrit précédemment. On rappelle que adj représente le tableau des tableaux d'adjacence Adj du graphe
, que parent représente l'arbre (en construction)
et on supposera que
n'appartient pas à
.
{debut = 1; fin = 4; suivant = [|-5; 2; 5; 3; -1; 4|]}
Q 17. Que peut-on dire de la terminaison de cet algorithme?
Q 18. Écrire une fonction
marche_aleatoire : int array array -> int array -> int -> chemin
telle que l'appel marche_aleatoire adj parent s renvoie l'objet c représentant un chemin de
L'algorithme d'évolution de
, appelé algorithme de Wilson, est alors le suivant : à partir de l'arbre
réduit à
, pour
variant de 0 à
, si
n'est pas dans
, on calcule un chemin de
à un sommet
codé par c grâce à la fonction marche_aleatoire et on greffe
à
, en ajoutant à
les arêtes du chemin
, orientées de
vers
étant le dernier sommet du chemin.
Q 19. Écrire une fonction
greffe : int array -> chemin -> unit
telle que l'instruction greffe parent c modifie parent de sorte à représenter l'arbre obtenu après la greffe du chemin sur
.
Q 20. Écrire une fonction
wilson : graphe -> int -> int array
tel que wilson gr renvoie un arbre couvrant aléatoire du graphe de racine
.
Q 19. Écrire une fonction
greffe : int array -> chemin -> unit
telle que l'instruction greffe parent c modifie parent de sorte à représenter l'arbre obtenu après la greffe du chemin
Q 20. Écrire une fonction
wilson : graphe -> int -> int array
tel que wilson gr renvoie un arbre couvrant aléatoire du graphe
IV Arbres couvrants et pavages par des dominos
Soient
et
deux entiers strictement supérieurs à 1 . Le but des deux dernières parties est de construire des pavages aléatoires par des dominos de taille
d'un échiquier à
colonnes et
lignes privé de son coin inférieur gauche (il reste bien un nombre pair de cases à recouvrir). Nous noterons
cet échiquier, dont les cases sont repérées par des couples de coordonnées entières (
), avec
et
, et
l'échiquier
privé de son coin inférieur gauche, c'est-à-dire de la case ( 0,0 ). Les cases de
sont colorées en noir, gris et blanc, comme dans l'exemple de l'échiquier
présenté figure 6.
Les cases dont les deux coordonnées sont paires sont colorées en noir, celles dont les deux coordonnées sont impaires sont colorées en gris, les autres sont colorées en blanc.
Si est un pavage de
, chaque case noire ou grise de
est recouverte par un domino, qui est orienté, à partir de la case noire ou grise considérée, vers le sud, l'ouest, le nord ou l'est.
Les cases dont les deux coordonnées sont paires sont colorées en noir, celles dont les deux coordonnées sont impaires sont colorées en gris, les autres sont colorées en blanc.
Si

Figure 6 L'échiquier
Nous définissons le type
type direction S | W | N | E
et nous codons par une matrice pavage de taille
, avec, pour
et
:
type direction
et nous codons
- si
et ont la même parité et si , p. (i). (j) est la direction du domino qui recouvre la case (cette case est soit noire, soit grise) ; - sinon, pavage. (i). (j) prend la valeur
(ces valeurs ne jouent aucun rôle).
Ainsi, si p1 est la matrice associée au pavage
de
représenté figure 7 (pour mieux distinguer les dominos, les cases ont été remplacées par des ronds colorés) on a par exemple p1.(2).(4) = S, p1.(4).(2) = W, p1.(3). (3)
, comme indiqué par les sens des flèches.

Figure 7 Le pavage
de
Les cases noires de l'échiquier
seront vues comme les sommets du graphe
(la case noire située en bas à gauche est identifiée au sommet 0 du graphe
). Un résultat de Neville Temperley explicite une bijection canonique
entre les pavages de
et les arbres couvrants de
. La construction de
à partir d'un pavage
s'obtient en ne conservant que les dominos recouvrant une case noire.
Pour toute la suite du sujet, les valeurs de et
seront supposées contenues dans les variables globales p et q . On suppose de plus définie une variable globale g , représentant
, par l'instruction
let quadrillage p q ;;
Pour toute la suite du sujet, les valeurs de
let
IV.A - Exemples
Q 21. Dessiner l'arbre couvrant non enraciné
de
.
Q 22. Considérons inversement l'arbre couvrant de
décrit figure 8. Par un procédé réciproque à celui utilisé à la question précédente, dessiner le pavage
de
.
Q 22. Considérons inversement l'arbre couvrant
IV.B - Calcul de l'arbre couvrant associé à un pavage
Q 23. Soit
un pavage de
, associé à l'arbre couvrant
de
. Décrire un procédé permettant de calculer le père d'un sommet
dans l'arbre
enraciné en 0 . On ne demande pas de démontrer que la structure ainsi obtenue est bien un arbre de racine 0 .

Figure 8 L'arbre couvant
Q 24. Écrire une fonction
coord_noire : int -> int * int
telle que l'instruction coord_noire s renvoie le couple des coordonnées de la case correspondant au sommet
du graphe
. Par exemple, dans le graphe
représenté figure 2 , coord_noire 6 renverra ( 4,2 ).
Q 25. Écrire une fonction
Q 25. Écrire une fonction
sommet_direction : int -> direction -> int
telle que sommet_direction
d renvoie le sommet
qui se trouve directement dans la direction d du sommet
de
. Cette fonction renverra -1 si un tel sommet n'existe pas. Par exemple, dans le graphe
représenté figure 2, sommet_direction 5 W renverra 4.
Q 26. Écrire une fonction
Q 26. Écrire une fonction
phi : direction array array -> int array
qui, appliquée à une matrice pavage représentant un pavage
de
, renvoie le tableau parent représentant l'arbre
enraciné en 0 (cette représentation est définie au début de la partie III).
V Utilisation du dual pour la construction d'un pavage
Graphe dual de
Le graphe
est un graphe planaire, c'est-à-dire qu'il possède une représentation graphique dans laquelle deux arêtes distinctes ne se coupent pas, sauf peut-être en leurs extrémités. Cette représentation planaire sépare le plan en
faces, que l'on va numéroter de gauche à droite et de bas en haut, la face non bornée portant le numéro 0 . Le graphe dual de
, noté
, est alors le graphe à
sommets (chaque sommet correspond à une des faces délimitées par la représentation de
) et qui possède autant d'arêtes que
: chaque arête
de
donne une arête
entre les deux faces du plan qu'elle sépare. Ce graphe est également planaire. Attention, contrairement au graphe
, le graphe
peut posséder plusieurs arêtes entre les mêmes sommets. Les sommets de
ont déjà été identifiés aux cases noires de
; les cases grises seront identifiées aux sommets de
distincts de 0 et les cases blanches aux arêtes de
(et donc également aux arêtes de
, puisque
est une bijection). La figure 9 explicite ces identifications dans le cas du graphe
. Les sommets de
sont identifiés par des sommets gris foncés, ceux de
par des sommets gris clairs, les arêtes de
par des traits pleins et celles de
par des traits hachurés. L'intersection de chaque (
) est marquée par un carré symbolisant une case blanche de
.
Ainsi, le sommet 6 de correspond à la case ( 4,2 ) de
, le sommet 4 de
correspond à la case ( 1,3 ) et les arêtes
de
et
de
correspondent à la case ( 3,0 ).
Dans la suite du problème, nous notons :
Ainsi, le sommet 6 de
Dans la suite du problème, nous notons :
-
le nombre de sommets de ;
le nombre de sommets de ; -
le nombre d'arêtes de et de ; -
l'ensemble des arêtes de ; -
l'ensemble des arêtes de .
Nous supposerons définies pour la suite :
- une fonction coord_grise : int -> int * int qui, appliquée à un sommet de
autre que 0 , renvoie les coordonnées de la case grise qui correspond à ce sommet ; - une fonction numero : int * int -> int qui, appliquée à un couple (
) représentant une case noire ou grise de l'échiquier , renvoie le sommet du graphe ou associé à cette case. On supposera également que dans tous les autres cas, numero renvoie la valeur 0 , y compris si les coordonnées sont en dehors de l'échiquier. Quand et , nous avons par exemple : numero , numero , et numero .

Figure
et
Q 27. En utilisant les fonctions précédentes, écrire une fonction
dual : unit -> graphe
telle que l'instruction dual () renvoie le graphe représentant . On respectera la numérotation des sommets de
décrite ci-dessus (figure 9). Par ailleurs, les listes d'adjacence du graphe dual contiendront des sommets en doublon s'il existe plusieurs arêtes entre des mêmes sommets.
On suppose désormais définie une variable globale g_etoile par l'instruction
let g_etoile = dual () ;;
V.B - Dual d'un arbre couvrant
dual : unit -> graphe
telle que l'instruction dual () renvoie le graphe représentant
On suppose désormais définie une variable globale g_etoile par l'instruction
let g_etoile = dual () ;;
V.B - Dual d'un arbre couvrant
Q 28. Montrer que, quitte à renuméroter les sommets, le dual de
est le graphe
.
Soit une partie de
. On note
la partie de
définie par
Soit
Q 29. Montrer que si le graphe (
) possède un cycle, le graphe (
) n'est pas connexe.
Q 30. En déduire que ( ) est un arbre couvrant de
si et seulement si (
) est un arbre couvrant de
.
Si est un arbre couvrant de
, nous noterons
l'arbre couvrant (
) de
.
Pour construire l'arbre , nous utiliserons une représentation différente des arbres que celle introduite en partie III : on pourra représenter un arbre couvrant
enraciné en
par un couple ( r , b) où b est un tableau de booléens de longueur
représentant
, c'est-à-dire tel que b. (i) prend la valeur true si et seulement si
.
La figure 10 représente les deux arbres couvrants du graphe , présenté en figure 5 , enracinés respectivement en 0 et 2 , et leurs représentations par un couple.
Q 30. En déduire que (
Si
Pour construire l'arbre
La figure 10 représente les deux arbres couvrants du graphe

Figure 10 Deux arbres couvrants enracinés de
et leurs représentations
Q 31. Écrire une fonction
vers_couple : int array -> int * bool array
telle que l'instruction vers_couple parent, où parent est un tableau représentant un arbre enraciné de , renvoie le couple (
, b) décrit ci-dessus.
vers_couple : int array -> int * bool array
telle que l'instruction vers_couple parent, où parent est un tableau représentant un arbre enraciné de
Q 32. Détailler en français un algorithme permettant de construire parent à partir du couple (
) et de la représentation du graphe
par listes d'adjacences. Cet algorithme est-il applicable à un arbre couvrant du graphe
? Justifier.
Q 33. Écrire une fonction
vers_parent : int * bool array -> int array
telle que l'instruction vers_parent ( ), où b désigne un ensemble
tel que (
) est un arbre de
enraciné en
, renvoie le tableau parent représentant cet arbre.
Q 34. Déterminer les complexités de ces deux fonctions de conversion en fonction de et
.
On supposera écrite une fonction vers_parent_etoile : int * bool array -> int array, ayant un fonctionnement similaire à vers_parent, qui prend en argument un couple (r, b_etoile) correspondant à un arbre couvrant de
et renvoie un tableau parent_etoile décrivant l'arbre en utilisant la représentation décrite partie III.
Q 35. Écrire une fonction
arbre_dual : int array -> int array
qui, appliquée au tableau parent représentant un arbre couvrant de
enraciné en 0 , renvoie le tableau parent_etoile représentant l'arbre couvrant
de
enraciné en 0 .
V.C - Calcul du pavage associé à un arbre couvrant
Q 33. Écrire une fonction
vers_parent : int * bool array -> int array
telle que l'instruction vers_parent (
Q 34. Déterminer les complexités de ces deux fonctions de conversion en fonction de
On supposera écrite une fonction vers_parent_etoile : int * bool array -> int array, ayant un fonctionnement similaire à vers_parent, qui prend en argument un couple (r, b_etoile) correspondant à un arbre couvrant
Q 35. Écrire une fonction
arbre_dual : int array -> int array
qui, appliquée au tableau parent représentant un arbre couvrant
V.C - Calcul du pavage associé à un arbre couvrant
Soit
un arbre couvrant de
.
Q 36. Décrire un procédé de construction, à partir des arbres et
enracinés en 0 , du pavage
de
. On expliquera en détail comment traiter les arêtes d'un sommet de
vers le sommet 0 . On justifiera brièvement que l'on obtient bien un pavage.
Q 37. Écrire une fonction
pavage_aleatoire : unit -> direction array array
telle que l'instruction pavage_aleatoire () renvoie une matrice de taille ( )(
) représentant un pavage aléatoire de
par des dominos.
Q 38. Comment adapter cette méthode à la construction de pavages aléatoires d'un échiquier à colonnes et
lignes (respectivement à
colonnes et
lignes) ?
Q 36. Décrire un procédé de construction, à partir des arbres
Q 37. Écrire une fonction
pavage_aleatoire : unit -> direction array array
telle que l'instruction pavage_aleatoire () renvoie une matrice de taille (
Q 38. Comment adapter cette méthode à la construction de pavages aléatoires d'un échiquier à
