diff --git a/Algorithmique/TD/TD0.md b/Algorithmique/TD/TD0.md
index 13779df5675426f1b987fe955b391bc090dcf8fd..9355fdec5b7ee2fe6e0973d6da9b088eaeaa7464 100644
--- a/Algorithmique/TD/TD0.md
+++ b/Algorithmique/TD/TD0.md
@@ -1,3 +1,11 @@
+---
+title: TD0
+author: VAN DE MERGHEL Robin
+date: 2023
+lang: fr
+geometry: margin=2cm
+---
+
 # Exercice 0.2
 
 ## 1.
diff --git a/Algorithmique/TD/TD0.pdf b/Algorithmique/TD/TD0.pdf
index 05325e48fc09b4209ff96da3fc0557dd61f67c19..6808765b1975a533449248de115ba03a1f9d66cc 100644
Binary files a/Algorithmique/TD/TD0.pdf and b/Algorithmique/TD/TD0.pdf differ
diff --git a/Algorithmique/TD/TD1.md b/Algorithmique/TD/TD1.md
index aeccbe2313a75d827a957c2d1b52f2bcf5898cf6..f6d55848b2dc5b6417e7580c2b3399d4c61c426a 100644
--- a/Algorithmique/TD/TD1.md
+++ b/Algorithmique/TD/TD1.md
@@ -1,3 +1,11 @@
+---
+title: TD1
+author: VAN DE MERGHEL Robin
+date: 2023
+lang: fr
+geometry: margin=2cm
+---
+
 # 1.3
 
 ## 1.
diff --git a/Algorithmique/TD/TD1.pdf b/Algorithmique/TD/TD1.pdf
index 819864f2e6ace2c235a3510c9f816b9b07588e43..3051383c078594604e54f24a1b888de52b80c10e 100644
Binary files a/Algorithmique/TD/TD1.pdf and b/Algorithmique/TD/TD1.pdf differ
diff --git a/Algorithmique/TD/TD2.md b/Algorithmique/TD/TD2.md
index 68d30cb553fb2ff6fb7778e0b1dd3dcf34a5aa7e..414a1bc0a1f5eae82be090076355278409ac9117 100644
--- a/Algorithmique/TD/TD2.md
+++ b/Algorithmique/TD/TD2.md
@@ -389,4 +389,171 @@ Liste concatener(Liste l1, Liste l2) {
 }
 ```
 
-Le temps est bien en $O(1)$ car on ne fait que modifier les pointeurs.
\ No newline at end of file
+Le temps est bien en $O(1)$ car on ne fait que modifier les pointeurs.
+
+
+
+## Question 2
+
+> **Expliquez comment utiliser les listes pour implémenter le TDA ensemble disjoint. Vous pourrez utiliser la réponse à la question précédente.**
+
+**Rappel du cours :**
+
+- `creerPartition(int n)` crée une partition où chaque partie est un singleton de $[n]$
+- `trouver(partie p, int x)` doit donner le représentant de la partie contenant $x$
+- `union(partie p, int x, int y)` doit faire l'union de sparties contenant $x$ et $y$
+
+### Ma version
+
+```ruby
+enregistrement Liste {
+    Element[] tab
+    int taille
+}
+
+enregistrement Element {
+    int val
+    Partie p
+}
+
+enregistrement Partie {
+    int id
+    Element debutPartie
+    Element finPartie
+}
+```
+
+```ruby
+Partie vide = -1
+Element vide = -1
+
+# O(1)
+# Car on a juste une allocation
+Element creerElement(int x) { # x est un entier
+    Element e = allocation()
+    e.val = x
+    e.p = vide
+    return e
+}
+
+# O(n)
+# Car on doit allouer n éléments
+# Chaque allocation est en O(1)
+Liste creerPartition(int n) {
+    Liste l = allocation()
+    l.tab = allocation(n)
+    l.taille = n
+    for (int i = 0; i < n; i++) {
+        l.tab[i] = creerElement(i)
+    }
+    return l
+}
+
+# O(1)
+# Car on a un tableau, et on peut accéder à l'élément en O(1)
+Partie trouver(Partie p, int x) {
+    return p.tab[x].p
+}
+
+# O(n)
+# Car pour chaque élément de la liste, on doit changer le pointeur
+# Changer le pointeur est en O(1)
+void union(Partie p, int x, int y) {
+    
+    Partie px = trouver(p, x)
+    Partie py = trouver(p, y)
+
+    Partie plusGrand
+    Partie plusPetit
+
+    Si taille(px) > taille(py) {
+        plusGrand = px
+        plusPetit = py
+    } Sinon {
+        plusGrand = py
+        plusPetit = px
+    }
+
+    Element e = plusPetit.debutPartie
+    Tant que e != vide, Faire {
+        e.p = plusGrand
+        e = e.suiv
+        plusPetit.finPartie.suiv = e
+        plusPetit.finPartie = e
+    }
+
+    plusGrand.finPartie.suiv = plusPetit.debutPartie
+    plusGrand.finPartie = plusPetit.finPartie
+
+    return p
+
+}
+```
+
+
+### Correction
+
+```ruby
+enregistrement Partition {
+    Liste<Liste<int>> parties
+}
+
+Partition creerPartition(int n) {
+    Partition p;
+    p.l = creerLise();
+
+    Pour i <- 1 à n, Faire {
+        s = creerListe();
+        insererDebut(s, i);
+        insererDebut(p.l, s);
+    }
+
+    Retourner p;
+}
+
+int trouver(Partition p, int x) {
+    Cellule c = debutliste(p.l)
+    Tant que finListe(c) == Faux, Faire {
+        Cellule c2 = debutListe(val(c))
+
+        Tant que finListe(c2) == Faux {
+            Si x == valeur(c2) {
+                Retourner valeur(c)
+            }
+            c2 = suivant(c2)
+        }
+
+        c = suivant(c)
+    }
+
+    Retourner -1
+}
+```
+
+Pour `trouver` : On suppose toujours que valeur suivant et debutListe sont en $O(1)$.
+
+La boucle `Tant Que` est extérieure fait au plus $k$ itérations, $k$ le nombre de parties.
+
+Pour chaque itération $i$, le nombre maximum d'itérations de la boucle est le nombre d'éléments de la partie parcourure à l'itération $i$, nommons cette taille $n_i$.
+
+Complexité en temps :
+
+$$\sum_{i=1}^k n_i$$
+
+Comme les parties sont disjointes, et que l'union des parties c'est l'ensemble à partitionner, $\sum_{i=1}^k = n_i = n$, où $n$ est la taille de l'ensemble à partitionner.
+
+Donc, la complexité est $\sum_{i=1}^k n_i = n$.
+
+```ruby
+Partition union(Partition p, int x, int y) {
+    l1 = trouver2(p,x) # O(n)
+    l2 = trouver2(p,y) # O(n)
+    concaténer(l1,l2) # O(n) ou O(1) selon l'implémentation
+    supprimer(p.l,l2) # O(nombre de parties) <= O(n)
+    retourner p
+}
+
+# On définit trouver 2 : 
+# Même chose que trouver, sauf que l'on retourne la liste contenant x
+# n = la taille de l'ensemble partitionné par p
+```
diff --git a/Algorithmique/TD/TD2.pdf b/Algorithmique/TD/TD2.pdf
index b3b24b1c63282c1d99a274170e5fb35db547d469..fecee3f16b6201bf1d930972758e7bc5d624fae6 100644
Binary files a/Algorithmique/TD/TD2.pdf and b/Algorithmique/TD/TD2.pdf differ
diff --git a/Algorithmique/TD/TD3.md b/Algorithmique/TD/TD3.md
new file mode 100644
index 0000000000000000000000000000000000000000..ee313dc959285cbc72f853dd93bfcf85f514ecbd
--- /dev/null
+++ b/Algorithmique/TD/TD3.md
@@ -0,0 +1,188 @@
+# Exercice 3.1
+
+## Question 1
+
+> **On implémente une arborescence avec le tableau `PERE`, i.e. dans chaque case on stocke l'index du père, et pour la racine on stocke la valeur $-1$. Proposer un algorithme (avec la meilleure complexité) pour chacune des opérations suivantes :**
+> - La racine de l'arbre
+> - La hauteur $h$ de l'arbre
+> - La liste des fils d'un noeud $x$
+> - Le sous-arbre issu d'un noeud $x$
+> - Tester si $x$ et $y$ sont frères
+
+```ruby
+# Racine de l'arbre
+# On cherche le premier élément du tableau qui vaut -1
+int racine(int[] pere) {
+    int i = 0;
+    while (pere[i] != -1) {
+        i++;
+    }
+    return i;
+}
+```
+
+La complexité en temps $O(l)$, où $l$ est le nombre d'itérations de `Tant que`. Comme $l$ peut être égal à $n-1$, la complexité en temps est $O(n)$.
+
+
+```ruby
+# Hauteur de l'arbre
+int hauteurNoeud(int Pere[n], int x) {
+    int h = 0;
+    int y = x;
+
+    while (Pere[y] != -1) {
+        h = h + 1;
+        y = Pere[y];
+    }
+
+    return h + 1;
+}
+```
+
+Si $h_x$ c'est la distance de la racine au noeud $x$, le nombre d'itérations c'est $h_x$. Donc la complexité en temps est $O(h_x)$.
+
+```ruby
+# Hauteur de l'arbre
+int hauteur(int Pere[n]) {
+    int h = 0;
+    int i = 0;
+
+    for (i = 0; i < n; i++) {
+        int h_i = hauteurNoeud(Pere, i);
+        if (h_i > h) {
+            h = h_i;
+        }
+    }
+
+    return h;
+}
+```
+
+Complexité : $n$ itérations, chaque itérations $O(h_i)$. Donc au total $\sum_{i=1}^n O(h_i) = O(\sum_{i=1}^n h_i) = O(n \cdot h)$.
+
+
+```ruby
+# Liste des fils d'un noeud x
+Liste listeFils(int Pere[n], int x) {
+    Liste liste = ListeVide();
+    int i = 0;
+
+    for (i = 0; i < n; i++) {
+        if (Pere[i] == x) {
+            liste = insererDebut(liste, i);
+        }
+    }
+
+    return liste;
+}
+```
+
+Si `insererDebut` est $O(1)$, la complexité en temps est $O(n)$.
+
+```ruby
+bool frere(int Pere[n], int x, int y) {
+    retourner Pere[x] == Pere[y];
+}
+```
+
+La complexité en temps est $O(1)$ car on n'accède qu'à deux cases du tableau.
+
+```ruby
+# Ensemble des feuilles
+Liste feuilles(int Pere[n]) {
+    bool[n] f;
+
+    # On met à vrai toutes les cases du tableau
+    for (i = 0; i < n; i++) {
+        f[i] = true;
+    }
+
+    for (i=0; i < n; i++) {
+        f[Pere[i]] = false;
+    }
+
+    Liste l = creerListe();
+    for (i = 0; i < n; i++) {
+        if (f[i]) {
+            l = insererDebut(l, i);
+        }
+    }
+
+    return l;
+
+}
+
+# Sous-arbre issu d'un noeud x
+liste sousArbre(int Pere[n], int x) {
+    Liste l = feuilles(Pere);
+
+    for (Feuille feuille in l) {
+        if (*En remontant comme dans la fonction hauteurNoeud on rencontre x*) {
+            *ajouter tous les noeuds entre f et x dans r*
+        }
+    }
+}
+```
+
+On peut vérifier que la complexité en temps est $O(n)$.
+
+## Question 2
+
+> **Comparer avec une implémentation où chaque noeud stocke une référence vers sont père, un premier fils vers sont frère de droite.**
+
+```mermaid
+graph TD
+A(Noeud) --> C(Pere)
+A --> B(Frere de droite)
+A --> D(Premier fils)
+```
+
+```mermaid
+graph TD
+5 --> 1
+1 --> 5
+1 --> 1
+5 --> 2
+2 --> 4
+4 --> 2
+2 --> 5
+2 --> 3
+3 --> 5
+3 --> 7
+7 --> 5
+```
+
+Le graphe ci-dessus représente les relations de l'arbre suivant :
+
+```mermaid
+graph TD
+5 --> 1
+5 --> 2
+5 --> 3
+5 --> 7
+2 --> 4
+```
+
+```ruby
+enregistrement arbre {
+    noeud racine
+}
+
+enregistrement noeud {
+    noeud pere
+    noeud filsG
+    noeud frereD
+    T val
+}
+
+fils(noeud n) {
+    l = creerListe();
+    noeud d = n.filsG;
+
+    while (d != null) {
+        l = insererDebut(l, d);
+        d = d.frereD;
+    }
+
+    return l;
+}
\ No newline at end of file
diff --git a/Algorithmique/TD/TD4.md b/Algorithmique/TD/TD4.md
index d4dc80af168af5b3daa9083ee54eacdb9828f37f..e715f6d575e5ae7eae8e26ca0dd1a9788f1db61e 100644
--- a/Algorithmique/TD/TD4.md
+++ b/Algorithmique/TD/TD4.md
@@ -1,3 +1,11 @@
+---
+title: TD4 Listes
+author: VAN DE MERGHEL Robin
+date: 2023
+lang: fr
+geometry: margin=2cm
+---
+
 # Exercice 4.1
 
 > **On a les codes suivants :**
@@ -84,20 +92,20 @@ On a donc $c_k \leq 1$ quand $n \geq \log_5(n)$. Donc la complexité est au pire
 
 On a :
 
-$$\begin{align} 
+$$\begin{aligned} 
     (n+a)^b &= \sum_{k=0}^b \binom{b}{k} a^{b-k} n^k \\
     &= n^k + \alpha_1 n^{k-1} + \alpha_2 n^{k-2} + \dots + \alpha_{k-1} n + \alpha_k \\
-\end{align}$$
+\end{aligned}$$
 
 Avec $\alpha_i = \binom{b}{i}$.
 
 On a donc :
 
-$$\begin{align}
+$$\begin{aligned}
     O((n+a)^b) &= O(n^b + \alpha_1 n^{b-1} + \alpha_2 n^{b-2} + \dots + \alpha_{b-1} n + \alpha_b) \\
     &= O(n^b) + O(\alpha_1 n^{b-1}) + O(\alpha_2 n^{b-2}) + \dots + O(\alpha_{b-1} n) + O(\alpha_b) \\
     &= O(n^b) + O(n^{b-1}) + O(n^{b-2}) + \dots + O(n) + O(1) \\
-\end{align}$$
+\end{aligned}$$
 
 On a $O(1)$ négligeable par rapport à $O(n)$, puis $O(n)$ négligeable par rapport à $O(n^2)$, etc. Jusqu'à $O(n^{b-1})$ qui est négligeable par rapport à $O(n^b)$. Donc $O((n+a)^b) = O(n^b)$.
 
diff --git a/Algorithmique/TD/TD4.pdf b/Algorithmique/TD/TD4.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..601f4643c9ed306f4ec4142130f92495370c1b66
Binary files /dev/null and b/Algorithmique/TD/TD4.pdf differ
diff --git a/Algorithmique/TD/td-listes.pdf b/Algorithmique/TD/td-listes.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..37021f44e45277da09c04968722e981b952c8248
Binary files /dev/null and b/Algorithmique/TD/td-listes.pdf differ