diff --git a/Images/uf_example.png b/Images/uf_example.png
new file mode 100644
index 0000000000000000000000000000000000000000..fe96b2244a1a228e2b135bbcf6e26b0a00a56dff
Binary files /dev/null and b/Images/uf_example.png differ
diff --git a/Images/uf_example.tex b/Images/uf_example.tex
new file mode 100644
index 0000000000000000000000000000000000000000..15b2641d2339d36dada16866c336f62161deb725
--- /dev/null
+++ b/Images/uf_example.tex
@@ -0,0 +1,47 @@
+\documentclass{standalone}
+\usepackage{tikz}
+
+\begin{document}
+
+\tikzset{
+  ufnode/.style={
+    circle,
+    draw,
+    thick
+  },
+  ufedge/.style={
+    -latex, 
+    thick
+  }
+}
+
+\begin{tikzpicture}
+  \draw
+  (0,1) node[ufnode] (n0) {0}
+  (1,2) node[ufnode] (n1) {1}
+  (2,1) node[ufnode] (n2) {2}
+  (5,1) node[ufnode] (n3) {3}
+  (6,2) node[ufnode] (n4) {4}
+  (7,1) node[ufnode] (n5) {5}
+  (7,0) node[ufnode] (n6) {6}
+  (10,1) node[ufnode] (n7) {7}
+  (10,2) node[ufnode] (n8) {8}
+  (13,2) node[ufnode] (n9) {9}
+  ;
+
+  \draw[ufedge] (n0) -- (n1) ;
+  \draw[ufedge] (n2) -- (n1) ;
+  \draw[ufedge] (n1) edge[loop above] (n1) ;
+
+  \draw[ufedge] (n3) -- (n4) ;
+  \draw[ufedge] (n5) -- (n4) ;
+  \draw[ufedge] (n6) -- (n5) ;
+  \draw[ufedge] (n4) edge[loop above] (n4) ;
+
+  \draw[ufedge] (n7) -- (n8) ;
+  \draw[ufedge] (n8) edge[loop above] (n8) ;
+
+  \draw[ufedge] (n9) edge[loop above] (n9) ;
+\end{tikzpicture}
+
+\end{document}
diff --git a/Images/uf_fusion.png b/Images/uf_fusion.png
new file mode 100644
index 0000000000000000000000000000000000000000..b2f723aed62e93af2e94046aa6eaa74cf4f430fc
Binary files /dev/null and b/Images/uf_fusion.png differ
diff --git a/Images/uf_fusion.tex b/Images/uf_fusion.tex
new file mode 100644
index 0000000000000000000000000000000000000000..55aeb55a83a747a9bbd64fc5c64c1b4910168e71
--- /dev/null
+++ b/Images/uf_fusion.tex
@@ -0,0 +1,56 @@
+\documentclass{standalone}
+\usepackage{tikz}
+
+\begin{document}
+
+\tikzset{
+  ufnode/.style={
+    circle,
+    draw,
+    thick
+  },
+  ufedge/.style={
+    -latex, 
+    thick
+  }
+}
+
+\begin{tikzpicture}
+  \draw
+  (0,1) node[ufnode] (n00) {0}
+  (1,2) node[ufnode] (n10) {1}
+  (2,1) node[ufnode] (n20) {2}
+  (4,1) node[ufnode] (n30) {3}
+  (5,2) node[ufnode] (n40) {4}
+  (6,1) node[ufnode] (n50) {5}
+  (6,0) node[ufnode] (n60) {6}
+
+  (0,1) +(10,0) node[ufnode] (n01) {0}
+  (1,2) +(10,0) node[ufnode] (n11) {1}
+  (2,1) +(10,0) node[ufnode] (n21) {2}
+  (4,1) +(10,0) node[ufnode] (n31) {3}
+  (5,2) +(10,0) node[ufnode] (n41) {4}
+  (6,1) +(10,0) node[ufnode] (n51) {5}
+  (6,0) +(10,0) node[ufnode] (n61) {6}
+  ;
+
+  \draw[ufedge] (n00) -- (n10) ;
+  \draw[ufedge] (n20) -- (n10) ;
+  \draw[ufedge] (n10) -- (n40) ;
+
+  \draw[ufedge] (n30) -- (n40) ;
+  \draw[ufedge] (n50) -- (n40) ;
+  \draw[ufedge] (n60) -- (n50) ;
+  \draw[ufedge] (n40) edge[loop above] (n4) ;
+
+  \draw[ufedge] (n01) -- (n11) ;
+  \draw[ufedge] (n21) -- (n11) ;
+  \draw[ufedge] (n11) edge[loop above] (n11) ;
+
+  \draw[ufedge] (n31) -- (n41) ;
+  \draw[ufedge] (n51) -- (n41) ;
+  \draw[ufedge] (n61) -- (n51) ;
+  \draw[ufedge] (n41) -- (n11) ;
+\end{tikzpicture}
+
+\end{document}
diff --git a/readme.md b/readme.md
index 8a722649fbc1150f88f7fbf42496f24cd3722eb4..374a1c11b1cd2b9a08ae5fcd4cc1cab9ee480d24 100644
--- a/readme.md
+++ b/readme.md
@@ -1 +1,179 @@
 # Structure Union Find et labyrinthes
+
+Le but de ce TP est d'aborder le problème de l'Union-Find, et la structure de
+données associée, et de l'appliquer pour la création de labyrinthes.
+
+## Union Find
+
+Le problème de l'union find est de gérer des ensembles disjoints d'objets : un
+objet ne peut pas appartenir à deux ensembles en même temps. Initialement, tous
+les objets sont dans leur propre ensemble, qui ne contient qu'eux. Il est
+ensuite proposé deux opérations :
+
+* l'*union* permet de joindre deux ensembles ;
+* la *recherche* permet de déterminer si deux objets sont dans le même ensemble.
+
+## Application à la création de labyrinthe
+
+### Un labyrinthe intéressant
+
+Ce TP vous propose d'appliquer la notion d'union find à la création de
+labyrinthes. Cette création de labyrinthes se base sur le principe suivant :
+
+* le labyrinthe est créé sur une grille carrée ;
+* au début chaque case de la grille est entourée de murs ;
+* petit à petit des murs sont abattus pour créer le labyrinthe.
+
+En appliquant naïvement ce principe, il est peu probable que le labyrinthe
+obtenu soit intéressant. Tout d'abord, si le nombre de murs n'est pas important,
+il est peu probable que l'entrée et la sortie du labyrinthe soient accessibles
+par un chemin. Ensuite ce procédé va vider le labyrinthes de ses murs sans créer
+les recoins tortueux qui rendent les labyrinthes intéressants.
+
+![labyrinthe naïf](Images/naive_maze.png)
+
+Pour obtenir un résultat plus intéressant, nous allons donc rajouter les deux
+contraintes suivantes :
+
+* depuis toute case, il est possible d'aller à toute autre case ;
+* il n'y a qu'un seul chemin possible pour aller d'une case à une autre.
+
+Les labyrinthes ainsi obtenus deviennent plus intéressants.
+
+![labyrinthe intéressant](Images/clever_maze.png)
+
+C'est pour mettre en place ces contraintes que l'Union-Find devient utile.
+
+### Lien entre Union-Find et labyrinthes
+
+Le principe est de dire que deux cases sont dans le même ensemble s'il existe un
+chemin pour aller de l'une à l'autre dans le labyrinthe. Initialement, toutes
+les cases sont entourées de murs, et donc chaque case est dans son propre
+ensemble qui ne contient qu'elle.
+
+Abattre le mur entre les cases $a$ et $b$ permet de créer un chemin entre ces
+deux cases. Ainsi, pour s'assurer de ne jamais créer plus d'un chemin pour
+aller d'une case à une autre, il suffit de ne jamais abattre de mur séparant des
+cases qui sont déjà reliées par un chemin. On utilisera donc la *recherche* pour
+déterminer si deux cases sont reliées par un chemin ou non.
+
+En créant un chemin entre la case $a$ et la case $b$, on crée en réalité des
+chemins entre toutes les cases qu'on pouvait atteindre depuis $a$ et toutes les
+cases qu'on pouvait atteindre depuis $b$. On réalise donc l'*union* de
+l'ensemble contenant $a$ et de l'ensemble contenant $b$.
+
+## Implémentation
+
+Ce dépôt contient un code de base pour gérer les grilles les afficher, abattre
+et monter des murs. Il vous reste donc à rajouter des fichiers pour la structure
+d'Union-Find et tout ce que vous trouvez utile, et à compléter le constructeur
+de la classe `Labyrinthe` pour abattre des murs et créer un labyrinthe
+intéressant.
+
+### Union-Find
+
+#### Arbres
+
+Le principe de l'Union-Find est fondé sur des arbres, mais contrairement aux
+arbres binaires que vous avez déjà manipulés, ces arbres stockent les liens de
+parenté de bas en haut : chaque nœud connaît son *parent*. Par convention, le
+parent de la racine de l'arbre est lui-même. Chaque arbre correspond à un
+ensemble disjoint. Initialement, chaque élément est donc la racine de son propre
+arbre, qui ne contient que lui.
+
+![exemple union find](Images/uf_example.png)
+
+Dans l'exemple ci dessus, l'Union-Find contient 4 ensembles, $0$ est l'enfant de
+$1$, $1$ est la racine de son arbre.
+
+Du point de vue de l'implémentation, le plus simple est d'identifier les $n$
+objets par les entiers de $[0,n-1]$. Un tableau `tab` d'entiers de taille $n$
+permet de stocker dans la case $i$ le numéro du parent de la case $i$. Dans
+l'exemple précédent, nous aurions donc le tableau
+
+```
+[1, 1, 1, 4, 4, 4, 5, 8, 8, 9]
+```
+
+#### Recherche
+
+Chaque ensemble est identifié par la racine de l'arbre qui le représente. La
+recherche consiste donc à suivre la chaîne de parents d'un nœud jusqu'à
+atteindre la racine de l'arbre. Pour déterminer si deux nœuds sont dans le même
+ensemble, on regarde si les racines de leurs arbres sont identiques.
+
+#### Union
+
+Pour unir deux ensemble, il suffit de s'assurer que deux arbres initialement
+distincts finissent avec la même racine. Il suffit donc de faire en sorte que le
+parent de l'une des deux racines devienne l'autre racine.
+
+Dans l'exemple précédent la fusion des deux premier arbres donnerait donc l'un
+des deux arbres suivants
+
+![exemple de fusion](Images/uf_fusion.png)
+
+Ce qui revient à renseigner 4 comme parent de 1
+
+```
+[1, 4, 1, 4, 4, 4, ...]
+```
+
+ou à renseigner 1 comme parent de 4
+
+```
+[1, 1, 1, 4, 1, 4, ...]
+```
+
+### Mise en place pour les labyrinthes
+
+Muni·e de cette base pour l'Union-Find, il est désormais possible de l'utiliser
+pour nos labyrinthes.
+
+#### Mélange des murs
+
+Pour que les labyrinthes soient intéressants, il est nécessaire d'essayer
+d'abattre l'ensemble des murs dans un ordre aléatoire. La première solution
+naïve serait de tirer un mur au hasard, et s'il est debout d'essayer de
+l'abattre. Dans la mesure où petit à petit il ne sera plus possible d'abattre la
+majorité des murs, cette solution finira par coûter très cher pour abattre les
+derniers murs, et il sera difficile également de savoir quand s'arrêter.
+
+La bonne solution consiste à créer une petite structure de votre choix pour
+représenter un mur entre deux cases, et de stocker dans un tableau tous les murs
+possibles. Vous pouvez ensuite mélanger ce tableau en utilisant l'algorithme vu
+en cours, ou les fonctionnalités de la librairie standard.
+
+Une fois le tableau mélangé, vous pouvez le parcourir linéairement, et essayer
+d'abattre chacun des murs qu'il contient. Après un passage, il n'est plus
+possible d'abattre le moindre mur, et le labyrinthe respecte les contraintes.
+
+#### Utilisation de l'Union-Find
+
+Pour utiliser votre Union-Find, vous pouvez numéroter implicitement toutes les
+cases de la grille en disant que la case à la ligne $l$ et la colonne $c$ est
+associée au numéro $l \times \mathrm{largeur} + c$.
+
+À chaque mur traité, récupérez les racines des arbres Union-Find des cases de
+part et d'autre. Si les racines sont les mêmes, les cases sont déjà reliées par
+un chemin, et le mur doit rester en place, sinon vous pouvez l'abattre, et
+fusionner les ensembles des deux cases.
+
+### Optimisation de l'Union-Find
+
+L'implémentation initiale de l'Union-Find proposée peut être coûteuse en terme
+de complexité. Dans le pire des cas, les fusions sont réalisées dans un ordre
+tel que les arbres sont en réalité des sortes de listes chaînées, qu'il faut
+parcourir d'un bout à l'autre pour en trouver la racine. La complexité dans le
+pire des cas pour une recherche est donc linéaire, et la fusion nécessitant de
+trouver les racines des deux arbres a la même complexité. Ces complexités
+peuvent être nettement améliorées grâce à deux idées simples à mettre en œuvre.
+
+#### Compression de chemin
+
+Lorsque vous cherchez la racine d'un arbre, vous partez d'un nœud et sautez de
+nœud en nœud pour la trouver. La compression de chemin fait en sorte qu'une fois
+la racine trouvée, tous les nœuds sur le chemin changent de parent, pour prendre
+directement la racine pour parente.
+
+#### Minimisation des hauteurs