diff --git a/TD07/INF-TC1-td07.ipynb b/TD07/INF-TC1-td07.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..c7262c5d015cd9ad1c850b77a17d85071eab22b1
--- /dev/null
+++ b/TD07/INF-TC1-td07.ipynb
@@ -0,0 +1,668 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "095a75fb",
+   "metadata": {},
+   "source": [
+    "NAME:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "57c2dc5b-0ce7-47e4-bfeb-445c2f90cb6e",
+   "metadata": {},
+   "source": [
+    "# INF TC1 - TD7 (2h) - Rendu de monnaie"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "2a40aa1b-c3fe-4cd2-9236-3c7aeddedf55",
+   "metadata": {},
+   "source": [
+    "---"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "25995ac6-8673-46f2-9c77-37b48a889b73",
+   "metadata": {},
+   "source": [
+    "## Objectif du TD\n",
+    "\n",
+    "Dans ce TD nous allons aborder le problème de rendu de monnaie selon plusieurs méthodes algorithmiques : \n",
+    "\n",
+    "- technique dite Gloutonne\n",
+    "- chemin minimal dans un arbre de recherche \n",
+    "- Programmation Dynamique (devoir à rendre)\n",
+    "\n",
+    "Vous serez amené également à créer une structure de données de graphe et une méthode de parcours de celui-ci. \n",
+    "\n",
+    "**Les réponses de la partie sur la programmation dynamique feront l'objet d'un autre sujet de TD et d'un rendu sous forme de rapport à rendre sur Moodle.**"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c38c9de3-f716-4907-8387-7cf6f4f5e926",
+   "metadata": {},
+   "source": [
+    "## Le problème de \"rendu de monnaie\"\n",
+    "\n",
+    "Le problème de rendu de monnaie est très fréquent dans la vie de tous les jours et peut être défini comme suit : étant donné un montant, une machine capable de rendre la monnaie doit rendre ce montant au client à partir de pièces (1c à 2€) et de billets. On suppose pour simplifier qu'il n'y a que des pièces en centimes; un billet de 5€ sera représenté comme une pièce de 500 centimes. On supposera dans un premier temps qu'il existe un nombre suffisant (autant que nécessaire) de chaque pièce, mais dans un second temps nous introduirons des contraintes de disponibilité des pièces."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5a29e913-8954-4e88-b477-234c4ee0fd9b",
+   "metadata": {},
+   "source": [
+    "|               | **la table S**         | **la table D**                   |\n",
+    "|---------------|------------------------|----------------------------------|\n",
+    "| **indice $i$**| **Valeur ($v_i$)**     | **Disponibilité ($d_i$)**        |\n",
+    "| 1             | 1c                     | nombre de pièces de 1c disponibles |\n",
+    "| 2             | 2c                     | nombre de pièces de 2c disponibles |\n",
+    "| 3             | 5c                     | ...                              |\n",
+    "| 4             | 10c                    | ...                              |\n",
+    "| 5             | 20c                    | ...                              |\n",
+    "| 6             | 50c                    | ...                              |\n",
+    "| 7             | 100 (1€)               | pièces de 1€                      |\n",
+    "| 8             | 200 (2€)               | pièces de 2€                      |\n",
+    "| 9             | 500 (5€)               | billets de 5€                     |\n",
+    "| 10            | 1000                   | billets de 10€                    |\n",
+    "| 11            | 2000                   | billets de 20€                    |\n",
+    "| 12            | 5000                   | billets de 50€                    |\n",
+    "| 13            | 10000                  | billets de 100€                   |\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "7f845f7b-8bd0-4544-8110-fa5ec1a7a960",
+   "metadata": {},
+   "source": [
+    "De manière plus formelle, un stock de pièces est un tuple $S=(v_1, v_2, ..., v_n)$ où l'entier $v_i > 0$ est la valeur de la $i^{ème}$ pièce. Pour refléter le fait qu'on a des pièces de 1, 2 et 5c, $S$ contiendra $v_1=1$ (1 centime), $v_2=2, v_3=5$. Le problème de monnaie est un problème d'optimisation combinatoire $(S,M)$ permettant de trouver le tuple $T=(x_1, x_2, ..., x_n)$ avec $x_i \\geq 0$ qui minimise $ \\sum_{i=1}^n x_i$ sous la contrainte $\\sum_{i=1}^n x_i.v_i=M$. Autrement dit, nous souhaitons aussi bien obtenir le montant exact, que minimiser le nombre total de pièces $x_i$ de valeur $v_i$ utilisées. Appelons $Q(S,M) = \\sum_{i=1}^n x_i$ la quantité de pièces à rendre pour le montant *M* étant donné le système *S* décrit dans la Table~1. Une solution optimale $Q_{opt}$ à ce problème est telle que *Q(S,M)* soit minimale :\n",
+    "\n",
+    "$Q_{opt}(S,M) = min \\ \\sum_{i=1}^n x_i$.\n",
+    "\n",
+    "Dans certaines situations il faudra gérer le nombre de pièces/billets disponibles (la table *D*). Nous noterons *d[i]=k* pour dire : il y a *k* pièces/billets du montant *$v_i$* disponibles (pièces ou billets du montant *v[i]*) à l'indice *i* dans la table *S*. On supposera cependant dans un premier temps qu'il y a un nombre suffisant de chaque pièce/billet dans le tableau S. On supposera également que *S* est ordonné dans un ordre croissant.\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "077ca702-bc18-4f2d-95e6-86fd4d53ebe7",
+   "metadata": {},
+   "source": [
+    "## Exemples\n",
+    "\n",
+    "**M = 9€:** étant donné S dans la Table ci-dessous, la solution qui minimise le nombre total de pièces rendues à 3 est *T=(0,0,0,0,0,0,0,2,1,0,0,0,0)*. Donc, $Q_{opt}(S,9) = \\min \\ Q(S,9) = 3$. Détails (avec des pièces $\\geq$ 1€) :\n",
+    "\n",
+    "\n",
+    "| Description                                            | T                                      | Rendu                                      | \n",
+    "|--------------------------------------------------------|----------------------------------------|---------------------------------------------|\n",
+    "| 9 pièces de 1€ et 0 pour toutes les autres            | T=(0,0,0,0,0,0,0,9,0,0,0...0)          | $\\rightarrow$ 9 pièces                      | $Q(S,9) =9$  |\n",
+    "| $\\circ$ 5 $\\times$ 1€ + 2 $\\times$ 2€, 0 pour les autres | T=(0,0,0,0,0,0,0,5,2,0,0...0)       | $\\rightarrow$ 7 pièces                      | $Q(S,9) =7$  |\n",
+    "| $\\circ$ 1 $\\times$ 1€ + 4 $\\times$ 2€, 0 pour les autres | T=(0,0,0,0,0,0,0,1,4,0,0...0)       | $\\rightarrow$ 5 pièces                      | $Q(S,9) =5$  |\n",
+    "| $\\circ$ 2 $\\times$ 2€ + 1 $\\times$ 5€, 0 pour les autres | T=(0,0,0,0,0,0,0,0,2,1,0...0)       | $\\rightarrow$ 3 pièces                      | **$Q(S,9) =3$** |\n",
+    "| $\\circ$ 3 $\\times$ 1 + 3 $\\times$ 2, 0 pour les autres  | T=(0,0,0,0,0,0,0,3,3,0,0...0)       | $\\rightarrow$ 6 pièces                      |              |\n",
+    "| $\\circ$ 4 $\\times$ 1 + 1 $\\times$ 5, 0 pour les autres  | T=(0,0,0,0,0,0,0,4,0,1,0...0)       | $\\rightarrow$ 5 pièces                      |              |\n",
+    "| $\\circ$ etc. sans parler des solutions avec des centimes ! |                                  |                                             |              |\n",
+    "<center>\n",
+    "    <i>Table 1</i>\n",
+    "</center>\n",
+    "\n",
+    "**M = 1989€:** pour rendre la somme de 1989€ pièces (sans les centimes), on aura : $1989 = 500 \\times 3 + 488 = 500 \\times 3 + 200 \\times 2 + 50 \\times 1 + 20 \\times 1 + 10 \\times 1 + 5 \\times 1 + 2 \\times 2$, soit $3+2+1+1+1 = 8$ grosses pièces (billets) et $1+2 = 3$ pièces.\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "254f7b95-aaeb-4f96-b8ec-47df74a3c3a3",
+   "metadata": {},
+   "source": [
+    "## Résolution du problème\n",
+    "\n",
+    "\n",
+    "L'exemple de la Table 1 est un système *canonique*, c'est à dire qu'en choisissant systématiquement les pièces de plus grande valeur (algorithme glouton) on obtient toujours la solution optimale. Il existe des systèmes pour lesquels c'est moins simple, par exemple $S=(1,7,23)$. Pour **M = 28**, en choisissant en priorité les pièces de plus grande valeur on trouvera $T=(5,0,1)$ (6 pièces), alors que la solution optimale est $T=(0,4,0)$ (4 pièces).\n",
+    "\n",
+    "Dans le cas général, ce problème est démontré NP-difficile, c'est-à-dire qu'on ne connaît pas d'algorithme qui puisse le résoudre en complexité polynomiale par rapport à la taille de $S$.\n",
+    "Il existe plusieurs approches :\n",
+    "\n",
+    "1. Approche gloutonne (pas toujours optimale) \n",
+    "2. Recherche de chemin de longueur minimale avec (ou sans) un arbre de recherche, ... \n",
+    "3. Programmation Dynamique, ... et autres méthodes algorithmiques (cf. quasi-Dijkstra)\n",
+    "  \n",
+    "Il existe d'autres approches de résolutions algorithmiques ou non-algorithmiques comme par exemple un système d'équations à optimiser. Nous allons dans ce TD aborder les différentes approches algorithmiques mentionnées ci-dessus.\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c8b2e4fe-cbfa-4301-89af-d02ea55473f0",
+   "metadata": {},
+   "source": [
+    "## Algorithme Glouton\n",
+    "\n",
+    "Les techniques de programmation gloutonnes ont la particularité de faire des choix locaux à chaque étape de calcul. Cette méthode ne donne pas forcément un nombre minimal de pièces mais elle est simple à comprendre et à implémenter. Son application au problème de rendu de monnaie est simple : on trouve la pièce la plus grande inférieure ou égale à $M$. Soit $v_i$ cette pièce. On utilise ($x_i  = M \\ div \\ v_i$) fois la pièce $v_i$; le reste à traiter sera $M'=(M \\mod v_i)$. Ensuite, on recommence suivant le même principe pour satisfaire $M'$. Ce qui donne le pseudo-code d'algorithme suivant (qui fait l'hypothèse d'un nombre illimité de pièces, on ne tient pas compte ici de $D$ : $d_i=\\infty$) :\n",
+    "\n",
+    "```\n",
+    "Fonction Monnaie_Gloutonne\n",
+    "Entrées : la somme S, M\n",
+    "Sorties : le vecteur  T = Q(S,M) : le nombre de pièces nécessaires \n",
+    "    M'=M\n",
+    "    Répéter\n",
+    "        Chercher dans S l'indice i tel que Vi =< M' \n",
+    "        Ti = M' div Vi\n",
+    "        M' = M' mod Si\n",
+    "    Jusqu'à M' = 0\n",
+    "\n",
+    "    Constituer T avec les Ti utilisés\n",
+    "        $Q(S,M) = somme de i=1 a i=n de T_i$ \n",
+    "    T est la valeur de sortie de l'algorithme\n",
+    "Fin Monnaie_Gloutonne\n",
+    "```\n",
+    "\n",
+    "Pour **M = 236,65€** cet algorithme se déroule de la manière suivante :\n",
+    "\n",
+    "$23665 \\geq 10000$\n",
+    "\n",
+    "  - $T_{13}=23665 \\ div \\ 10000 = 2$ ($T_{13}$ correspond à 100€)\n",
+    "  - $M'=23665 \\ mod \\ 10000 = 3665$ \n",
+    "\n",
+    "$3665 \\geq 2000$\n",
+    "\n",
+    "  - $T_{11}=3665 \\ div \\ 2000 = 1$\n",
+    "  - $M'=3665 \\ mod \\ 2000 = 1665$\n",
+    "      ...\n",
+    "      \n",
+    "$\\rightarrow$ On obtient $T_{1..13}=(0,0,1,1,0,1,1,0,1,1,1,0,2)$ et $Q(S,M) = 9$\n",
+    "\n",
+    "A noter qu'en Python les indices commencent à zéro ! Faire -1 sur les indices ci-dessus.\n"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "425fe58a-b0bc-41eb-acea-0d88e1daf18f",
+   "metadata": {},
+   "source": [
+    "**Question 1.1 -** Implémenter l'algorithme glouton ci-dessus."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "e3880c0c-4c2c-48c4-96b1-0c95c712b489",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "70c7babeb5e85cc22c905a8f4bdf6271",
+     "grade": false,
+     "grade_id": "cell-9e328bc8eab0c35d",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def gloutonne(S: list, M: int) -> list:\n",
+    "    \"\"\"\n",
+    "    Algorithme glouton\n",
+    "\n",
+    "    Args:\n",
+    "    - S (list): Une liste d'entier représentant les pièces\n",
+    "    - M (int): La somme à atteindre\n",
+    "\n",
+    "    Returns:\n",
+    "    - list: (True, Q(S,M)) si succès OU (False, None) si échec.\n",
+    "    \"\"\"\n",
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "2a39cbfb-d35d-4da7-bbaa-d273bc900c2d",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "Les tests suivants doivent être validés :"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "90cd609d-71d9-41b0-ba28-c66fd94a2524",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "Rep= gloutonne([1,7,23], 28)\n",
+    "print(Rep,  ': ', sum(Rep),' pieces') if Rep else print('Echec') \n",
+    "# [5, 0, 1] :  6  pieces\n",
+    "\n",
+    "Rep= gloutonne([7,23], 5)\n",
+    "print(Rep,  ': ', sum(Rep),' pieces') if Rep else print('Echec') \n",
+    "# Echec car M < la + petite pièce\n",
+    "\n",
+    "Rep= gloutonne([7,23], 8)\n",
+    "print(Rep,  ': ', sum(Rep),' pieces') if Rep else print('Echec') \n",
+    "# Echec car on ne peut jamais faire la monnaie avec cette S\n",
+    "\n",
+    "Rep= gloutonne([1,5,10,25], 63)\n",
+    "print(Rep,  ': ', sum(Rep),' pieces') if Rep else print('Echec') \n",
+    "# [3, 0, 1, 2] :  6  pieces"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c5d61f32-13cc-4176-8f47-b0ca861a74ba",
+   "metadata": {},
+   "source": [
+    "**Question 1.2 -** Proposez une modification du pseudo-code ci-dessus pour prendre en compte un nombre **limité** de pièces (en prenant en compte la table $D$). Implémenter cet algorithme modifié (vous fournirez vos propres valeurs de disponibilité dans $D$)."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "91951f93-bf34-4ea9-ad08-76c73ff3ce44",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "3ab8caefe1e647443f941efd8646aabf",
+     "grade": false,
+     "grade_id": "cell-f55f05cae03e7c51",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def gloutonne_avec_D(S: list, M: int, D: int) -> tuple:\n",
+    "    \"\"\"\n",
+    "    Algorithme glouton avec nombre limité de pièces\n",
+    "\n",
+    "    Args:\n",
+    "    - S (list): Une liste d'entier représentant les pièces\n",
+    "    - M (int): La somme ) à atteindre\n",
+    "    - D (int): La disponibilité des pièces\n",
+    "    \n",
+    "    Returns:\n",
+    "    - list: (True, Q(S,M)) si succès OU (False, None) si échec.\n",
+    "    \"\"\"\n",
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "9786ca50-6bfe-491d-8971-89be91ccfd8b",
+   "metadata": {},
+   "source": [
+    "Les tests suivants doivent être validés :"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b5af3022-65fe-4877-99ce-23de3843a5ec",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "Rep= gloutonne_avec_D([1,7,23], 28,[10,10,10])\n",
+    "print(Rep,  ': ', sum(Rep),' pieces') if Rep else print('Echec') \n",
+    "# [5, 0, 1] :  6  pieces\n",
+    "\n",
+    "Rep= gloutonne_avec_D([1,7,23], 28,[10,10,0])\n",
+    "print(Rep,  ': ', sum(Rep),' pieces') if Rep else print('Echec') \n",
+    "# [0, 4, 0] :  4  pieces\n",
+    "\n",
+    "Rep= gloutonne_avec_D([1,5,10,25], 63, [1,0,3,2])\n",
+    "print(Rep,  ': ', sum(Rep),' pieces') if Rep else print('Echec') \n",
+    "# Echec"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "70534a4f-cc60-4c29-b5e6-1392126fc9f5",
+   "metadata": {},
+   "source": [
+    "Vous noterez que la méthode Gloutonne ne garantit pas que *Q(S, M)* soit minimal comme les tests l'ont montré pour M=28 et S=(1, 7, 23).  La méthode Gloutonne utilise un optimum local (choix de la plus grande pièce) qui ne débouche pas forcément sur un optimum global. Cependant, elle est très simple à calculer."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "321b284b-a735-47b5-a889-ef52006c967e",
+   "metadata": {},
+   "source": [
+    "## Chemin minimal dans un arbre\n",
+    "\n",
+    "Une deuxième méthode consiste à construire toutes les solutions possibles sous forme d'arbre, et ensuite de choisir la solution de manière globale. Cette méthode est plus complexe à mettre en oeuvre mais donne une solution optimale."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "431ee4d7-1fa8-4bfd-bf9c-ec0725d08e5b",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "<center>\n",
+    "<img src=\"monnaie-graph.png\" alt=\"Image originale\" style=\"height:10cm;\">\n",
+    "</center>\n",
+    "    \n",
+    "Exemple d'arbre de recherche résultant *M=28* et *S=(1,7,23)*. C'est à dire, on a seulement des pièces de 1, 7 et 23 (€ ou cents) en nombre suffisant. Dès qu'on atteint 0, on remonte de ce 0 à la racine pour obtenir la solution minimale donnant le nombre minimal d'arcs entre ce 0 et la racine. On remarque qu'on utilisera 4 pièces de 7c pour avoir 28c. Par ailleurs, on remarque que le choix initial de 23 (à gauche de l'arbre) laisse le montant *M'=5c* à satisfaire lequel impose le choix de 5 pièces de 1c. En bleu les autres chemins choisissant une pièce de 23."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "36bc9ae5-81f2-4f12-9b94-03d90db050c0",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "On construit un arbre de recherche (arbre des possibilités) dont la racine est *M*. Chaque noeud de l'arbre représente un montant : les noeuds autres que la racine initiale représentent $M' < M$ une fois qu'on aura utilisé une (seule) des pièces de $S$ (parmi 1, 7 ou 23€). La pièce utilisée pour aller de $M$ à $M'$ sera la valeur de l'arc reliant ces deux montants. Cet arbre est donc développé par niveau (en largeur). On arrête de développer un niveau supplémentaire dès qu'un noeud a atteint 0 auquel cas une solution sera le vecteur des valeurs (des arcs) allant de la racine à ce noeud.\n",
+    "\n",
+    "Le principe de l'algorithme correspondant à un parcours en largeur dont la version itérative utilise une *File d'attente* est :\n",
+    "\n",
+    "```\n",
+    "Fonction Monnaie_graphe\n",
+    "% on suppose qu'il y a un nombre suffisant de chaque pièce/billet dans la tableau S\n",
+    "Entrées : la somme M\n",
+    "Sorties : le vecteur T et Qopt(S,M) le nombre de pièces nécessaires \n",
+    "    File F = vide ;\n",
+    "    Arbre A contenant un noeud racine dont la valeur = M\n",
+    "    Enfiler(M)                  % la file F contient initialement M\n",
+    "    Répéter\n",
+    "        M'= défiler()\n",
+    "        Pour chaque pièce vi =< M'  disponible dans S :\n",
+    "              S'il existe dans l'arbre A un noeud dont la valeur est M' - vi\n",
+    "              Alors établir un arc étiqueté par vi allant de M' à ce noeud\n",
+    "              Sinon \n",
+    "                Créer un nouveau noeud de valeur M' - vi dans A et lier ce noeud \n",
+    "                à M' par un arc  étiqueté par vi\n",
+    "                Enfiler ce nouveau noeud \n",
+    "              Fin Si\n",
+    "    Jusqu'à (M' - vi = 0) ou (F = vide)\n",
+    "\n",
+    "    Si (F est vide Et M' - vi /= 0) \n",
+    "    Alors il y a un problème dans les calculs ! STOP.\n",
+    "    Sinon Le dernier noeud créer porte la valeur 0\n",
+    "          On remonte de ce noeud à la racine et on comptabilise dans T où \n",
+    "          Ti = le nombre d'occurrences des arcs étiquetés vi de la racine \n",
+    "          au noeud v de valeur 0 \n",
+    "          $Q(S,M) = somme de i=1 a i=n de T_i$                      \n",
+    "    Fin si\n",
+    "Fin Monnaie_graphe\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d15c2fca-64f1-4d6d-b6bf-5edf9b095828",
+   "metadata": {},
+   "source": [
+    "**Question 2.1 -** Ecrire un algorithme de construction de l'arbre."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "2d2556ed-8be9-416f-a976-8964ccca8061",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "e4931d4223af65908a9483524ef0aaf3",
+     "grade": false,
+     "grade_id": "cell-26a3f71f49082689",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def Monnaie_graphe(S: list, M: int) -> dict:\n",
+    "    \"\"\"\n",
+    "    Génère un graphe représentant les combinaisons de pièces possibles pour atteindre un montant spécifié\n",
+    "    en utilisant un ensemble donné de valeurs de pièces.\n",
+    "\n",
+    "    Args:\n",
+    "    - S (list): Une liste d'entiers représentant les valeurs disponibles des pièces.\n",
+    "    - M (int): Un entier spécifiant le montant cible à atteindre.\n",
+    "\n",
+    "    Returns:\n",
+    "    - dict: Un graphe (représenté sous forme de dictionnaire)\n",
+    "    \"\"\"\n",
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "c2709c24-bbe0-4c6a-aaf8-f2e3712131f5",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "A = Monnaie_graphe([1, 2, 5], 7)\n",
+    "print(\"Arbre créé\", A)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "91d7262d-9a9c-4f22-b60e-6d43267a59bb",
+   "metadata": {},
+   "source": [
+    "Vous devriez pouvoir visualiser votre arbre avec la méthode `plot_graph` (chargez d'abord les dernières cellules du notebook afin d'initialiser cette fonction) :"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "701a7359-145f-4077-a8ee-e056eb3447f1",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "plot_graph(A)"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "9de0a303-b587-4901-b0ac-68a7cd04bfc7",
+   "metadata": {},
+   "source": [
+    "**Question 2.2 -** Ecrire un algorithme de recherche du chemin le plus court dans l'arbre."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "f5f033d8-1d49-49c7-9af7-e1cd59905d96",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "48d1848eeb1420cd93c7db5eb2e69531",
+     "grade": false,
+     "grade_id": "cell-d0ccbc035284ee45",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def plus_court_chemin(graph: dict, start: str):\n",
+    "    \"\"\"\n",
+    "    Calcule les distances les plus courtes depuis un nœud de départ dans un graphe.\n",
+    "\n",
+    "    Args:\n",
+    "    - graph (dict): Un dictionnaire représentant le graphe\n",
+    "    - start (str): Le nœud de départ à partir duquel calculer les distances.\n",
+    "\n",
+    "    Returns:\n",
+    "    - int: la taille du chemin\n",
+    "    \"\"\"\n",
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "7aca69d8-79ed-4f06-bb25-5c42b116cbc8",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert plus_court_chemin(A, 3)[0] == 2"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "72832556-e0d7-4959-8d93-2b55145e7c25",
+   "metadata": {},
+   "source": [
+    "**Question 2.3 -** Compléter l'algorithme précédent avec un mécanisme de backtracking permettant de retourner le plus court chemin utilisé."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "636ed054-38e5-46d1-b44f-c2d861bf1cc0",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "4240237ebdb351af86770db97de31e41",
+     "grade": false,
+     "grade_id": "cell-6a35215f9436c840",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def plus_court_chemin_backtracking(graph: dict, start: str):\n",
+    "    \"\"\"\n",
+    "    Calcule les distances les plus courtes depuis un nœud de départ dans un graphe.\n",
+    "\n",
+    "    Args:\n",
+    "    - graph (dict): Un dictionnaire représentant le graphe\n",
+    "    - start (str): Le nœud de départ à partir duquel calculer les distances.\n",
+    "\n",
+    "    Returns:\n",
+    "    - tuple: le chemin utilisé et les montants intermédiaires\n",
+    "    \"\"\"\n",
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b0253f7c-0f07-436c-b72c-2411fb757e47",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "assert plus_court_chemin_backtracking(A, 7) == [7, 5, 0]"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "f358da32-9534-493c-80b1-60d387f89229",
+   "metadata": {},
+   "source": [
+    "A noter que vous pouvez combiner la construction et la recherche du plus court chemin (en vous arrêtant au premier 0 rencontré). Cependant, cette methode a pour inconvénient d'explorer un très large espace de recherche (qui devient vite très grand). Un autre inconvénient est le calcul de solutions dont on sait qu'elles ne seront pas optimales."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "91af94f8-c687-4739-b4fb-ef58cb7e6081",
+   "metadata": {},
+   "source": [
+    "## Utils"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "7cbf74a0-525c-4b6f-b078-5f0eea6fe09d",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "from graphviz import Digraph\n",
+    "from IPython.display import display, Image\n",
+    "import graphviz"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "83f489e1-8fb7-45ec-a906-4d2699c63a46",
+   "metadata": {
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "def plot_graph(graph):\n",
+    "    dot = graphviz.Digraph()\n",
+    "\n",
+    "    for node in graph:\n",
+    "        dot.node(str(node))\n",
+    "\n",
+    "    for node, neighbors in graph.items():\n",
+    "        for neighbor, weight in neighbors.items():\n",
+    "            dot.edge(str(node), str(neighbor), label=str(weight))\n",
+    "    display(dot)"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.10.9"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/TD07/monnaie-graph.png b/TD07/monnaie-graph.png
new file mode 100644
index 0000000000000000000000000000000000000000..52c3621f835e749a3f3fd6bcf6a397bc957df5e9
Binary files /dev/null and b/TD07/monnaie-graph.png differ
diff --git a/TD07/monnaie-progdyn.png b/TD07/monnaie-progdyn.png
new file mode 100644
index 0000000000000000000000000000000000000000..a6408fadd0057db8f338b3817ddc588d2a1f4c33
Binary files /dev/null and b/TD07/monnaie-progdyn.png differ