diff --git a/TD07/INF-TC1-td07.ipynb b/TD07/INF-TC1-td07.ipynb
index 5d49d015a60501f4b1ade78af0f8dfa28cbbb332..20bf92f10be537090ff11780092bdc1f66515961 100644
--- a/TD07/INF-TC1-td07.ipynb
+++ b/TD07/INF-TC1-td07.ipynb
@@ -2,7 +2,7 @@
  "cells": [
   {
    "cell_type": "markdown",
-   "id": "52685e4b",
+   "id": "7ef4a973",
    "metadata": {},
    "source": [
     "NAME:"
@@ -35,7 +35,7 @@
     "\n",
     "- technique dite Gloutonne\n",
     "- chemin minimal dans un arbre de recherche \n",
-    "- Programmation Dynamique (devoir à rendre)\n",
+    "- Programmation Dynamique (**prochain TD7bis et 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",
@@ -138,7 +138,7 @@
    "id": "c8b2e4fe-cbfa-4301-89af-d02ea55473f0",
    "metadata": {},
    "source": [
-    "## Algorithme Glouton\n",
+    "## 1. 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",
@@ -193,7 +193,7 @@
     "deletable": false,
     "nbgrader": {
      "cell_type": "code",
-     "checksum": "d997ace798b6608a2375d443b277dcbb",
+     "checksum": "f8e488676f9c27a4f9be6294afa7a0a4",
      "grade": false,
      "grade_id": "cell-9e328bc8eab0c35d",
      "locked": false,
@@ -207,7 +207,7 @@
    "source": [
     "def gloutonne(S: list, M: int) -> tuple:\n",
     "    \"\"\"\n",
-    "    Algorithme glouton\n",
+    "    Algorithme glouton sans nombre limité de pièces\n",
     "\n",
     "    Args:\n",
     "    - S (list): Une liste d'entier représentant les pièces\n",
@@ -331,7 +331,7 @@
    "id": "321b284b-a735-47b5-a889-ef52006c967e",
    "metadata": {},
    "source": [
-    "## Chemin minimal dans un arbre\n",
+    "## 2. 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."
    ]
@@ -486,7 +486,7 @@
     "deletable": false,
     "nbgrader": {
      "cell_type": "code",
-     "checksum": "48d1848eeb1420cd93c7db5eb2e69531",
+     "checksum": "e7d213b1e3e06cd9359588f370c43eaf",
      "grade": false,
      "grade_id": "cell-d0ccbc035284ee45",
      "locked": false,
@@ -498,7 +498,7 @@
    },
    "outputs": [],
    "source": [
-    "def plus_court_chemin(graph: dict, start: str):\n",
+    "def plus_court_chemin(graph: dict, start: str) -> int:\n",
     "    \"\"\"\n",
     "    Calcule les distances les plus courtes depuis un nœud de départ dans un graphe.\n",
     "\n",
@@ -541,7 +541,7 @@
     "deletable": false,
     "nbgrader": {
      "cell_type": "code",
-     "checksum": "4240237ebdb351af86770db97de31e41",
+     "checksum": "460f4cd88d1c1dba779dbd4decc953fb",
      "grade": false,
      "grade_id": "cell-6a35215f9436c840",
      "locked": false,
@@ -553,7 +553,7 @@
    },
    "outputs": [],
    "source": [
-    "def plus_court_chemin_backtracking(graph: dict, start: str):\n",
+    "def plus_court_chemin_backtracking(graph: dict, start: str) -> list:\n",
     "    \"\"\"\n",
     "    Calcule les distances les plus courtes depuis un nœud de départ dans un graphe.\n",
     "\n",
@@ -562,7 +562,7 @@
     "    - 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",
+    "    - list: le chemin utilisé et les montants intermédiaires\n",
     "    \"\"\"\n",
     "# YOUR CODE HERE\n",
     "raise NotImplementedError()"
diff --git a/TD07/INF-TC1-td07bis.ipynb b/TD07/INF-TC1-td07bis.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..8fa2b59f71227d28bc085ad24cf3e1b312a41968
--- /dev/null
+++ b/TD07/INF-TC1-td07bis.ipynb
@@ -0,0 +1,476 @@
+{
+ "cells": [
+  {
+   "cell_type": "markdown",
+   "id": "2c7e0986",
+   "metadata": {},
+   "source": [
+    "NAME:"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "57c2dc5b-0ce7-47e4-bfeb-445c2f90cb6e",
+   "metadata": {},
+   "source": [
+    "# INF TC1 - TD7bis (2h + 2h AUTO) - Rendu du 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 rendu de TD est d'aborder le problème de rendu de monnaie selon la méthode de **Programmation Dynamique**.\n",
+    "\n",
+    "**Vos réponses à ce TD fera l'objet d'un rendu à [déposer sur Moodle](https://pedagogie1.ec-lyon.fr/course/view.php?id=1865).**\n",
+    "\n",
+    "## Modalités de rendu du TD\n",
+    "\n",
+    "Le rendu sera à déposer sur Moodle une (1) semaine après le dernier TD d'autonomie. Il pourra être réalisé seul ou en binôme. Ce rendu devra comporter :\n",
+    "\n",
+    "- Les réponses aux questions de la partie 3 sous forme de notebook ou autre document.\n",
+    "\n",
+    "- Un code fonctionnel et les tests appropriés (avec `assert` par exemple) sous forme de notebook ou de fichier Pythons classiques.\n",
+    "  \n",
+    "- De **nombreux** tests avec plusieurs systèmes de monnaies (canoniques et non canoniques) démontrant l'efficacité de votre approche. **Pensez également à inclure des tests démontrant les limites des solutions que vous proposez.** Pensez à rajouter les types de variables et commentaires dans les fonctions.\n",
+    "\n",
+    "- La description de parties de code difficiles (dans le code ou dans des cellules supplémentaires).\n",
+    "\n",
+    "- Tout soucis ou point bloquant dans votre code.\n",
+    "\n",
+    "- Les diagrammes, exemples et illustration nécessaires (dans ce cas vous devrez créer une archive comprenant les fichiers de code, notebook et les fichiers d'illustration).\n",
+    "\n",
+    "- Tout élément et exemple supplémentaire que vous jugerez nécessaires."
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "1fcb1349-4cae-4f76-b3b6-d9a810225afe",
+   "metadata": {},
+   "source": [
+    "NOM(s) et PRENOM(s) :\n",
+    "\n",
+    "Groupe de TD :"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "c38c9de3-f716-4907-8387-7cf6f4f5e926",
+   "metadata": {},
+   "source": [
+    "## Rappel: 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": "6c6aef6c-c6b7-4376-a0dd-06346df476df",
+   "metadata": {},
+   "source": [
+    "## 3. Algorithme de Programmation Dynamique (Rendu du TD)\n",
+    "\n",
+    "Nous introduisons une troisième et dernière méthode de résolution qui se base sur la programmation dynamique dont les principes sont :\n",
+    "\n",
+    "1) identifier une formule récursive pour résoudre le problème de façon incrémentale, \n",
+    "2) résoudre le problème pour des conditions aux bords,\n",
+    "3) itérer pour résoudre le problème complet. \n",
+    "\n",
+    "Supposons que l'on puisse, pour le montant *M*, savoir calculer une solution optimale pour tout montant $M' < M$. Pour satisfaire *M*, il faudra alors prendre une (seule) pièce $v_i$ supplémentaire parmi les *n* pièces disponibles. Une fois cette pièce choisie, le reste $M' = M-v_i$  est forcément inférieur à *M* et on sait qu'on peut calculer un nombre optimal de pièces pour *M'*. Par conséquent :  "
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "53272a7f-ff93-4143-83cd-f33e1750b0b2",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "\n",
+    "$Q_{opt}(i,m) = min\n",
+    "\\begin{cases}\n",
+    "  1 + Q_{opt}(i, m - v_i) \\quad si \\ (m - v_i) \\geq 0  \\qquad \\text{ on utilise une pièce de type i de \n",
+    "  valeur $v_i$}\\\\\n",
+    "Q_{opt}(i-1, m) \\qquad \\quad    si \\ i \\geq 1 \\qquad \\qquad \\quad \\text{ on n'utilise pas la pièce de type i, \n",
+    "essayons i-1}\n",
+    "\\end{cases}$\n",
+    "\n",
+    "\n",
+    "L'inconvénient de cette méthode est que chaque appel à $Q_{opt}$ fait deux appels à lui-même, donc le nombre d'opérations nécessaires est exponentiel à la taille de *M*. Pour éviter cela ferons appel au principe de *mémoïsation* de la programmation dynamique, en stockant les résultats intermédiaires dans une matrice $mat[|S|][M]$ (Figure 2).\n",
+    "\n",
+    "<center>\n",
+    "<img src=\"monnaie-progdyn.png\" alt=\"Image originale\" style=\"height:5cm;\">\n",
+    "</center>\n",
+    "<center>\n",
+    "    <i>Figure 2</i>\n",
+    "</center>\n",
+    "    \n",
+    "Illustration de la résolution par programmation dynamique. L'ordre de remplissage des cellules (de haut en bas, de gauche à droite) est représenté en vert.\n",
+    "\n",
+    "Les colonnes de la matrice sont les valeurs de M qu'on doit atteindre. Les lignes sont les pièces dont on dispose pour atteindre chaque valeur de M. En première ligne, on ne dispose d'aucune pièce, en ligne 2 on dispose d'une infinité de pièces de 1c, en ligne 3 on dispose d'une infinité de pièces de 1c et de 3c, etc. Les cellules de la matrice indiquent le nombre minimal de pièces à utiliser parmi celles autorisées par la ligne courante, pour atteindre la valeur en colonne. Ainsi on peut lire dans la matrice que pour payer 6 centimes avec des pièces de 1, 3 et 4 il faut utiliser 2 pièces (2 $\\times$ 3c). Le remplissage de chaque cellule se fait en calculant le minimum de deux voisins (illustrés avec des flèches rouges). Si un voisin est hors de la matrice, il ne compte pas dans le calcul du minimum. Le pseudo-code de construction de la matrice peut s'écrire de la façon suivante :\n",
+    "\n",
+    "```\n",
+    "fonction Progdyn(S, M) : S est le stock des pièces, M est le montant\n",
+    "    soit mat la matrice d'indices [0, |S|] x [0 , M]\n",
+    "    pour i = 0 à |S| faire\n",
+    "      pour m = 0 à M faire\n",
+    "        si m = 0 alors\n",
+    "          mat[i][m] = 0\n",
+    "        sinon si i = 0 alors\n",
+    "          mat[i][m] = infini\n",
+    "        sinon\n",
+    "          mat[i][m] = min(\n",
+    "            si m - S[i-1] >= 0 alors 1 + mat[i][m - S[i-1]] sinon infini\n",
+    "            si i >= 1 alors mat[i-1][m] sinon infini\n",
+    "            )\n",
+    "    renvoyer mat [|S|][M]\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "1287c1b0-4900-4b18-ab59-5719f867e18d",
+   "metadata": {
+    "tags": []
+   },
+   "source": [
+    "**Question 3.1 -** Proposer une solution Python de cette méthode. Dans une première étape, trouver simplement le nombre minimal de pièces. Renvoyer `None` si il n'existe pas de solution possible."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "fc6d6123-9d62-4d58-a9c7-dd0540c77d9c",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "d9be2aca674cf1ffd32edf6ea36d3b74",
+     "grade": false,
+     "grade_id": "cell-ee519b103bb353c7",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "90172789-470c-452d-96ff-8adc56d8c134",
+   "metadata": {},
+   "source": [
+    "**Question 3.2 -** Modifier votre solution pour renvoyer également les pièces utilisées."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "51354054-3292-48c6-8d43-8f42ffd11127",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "44e9b1662ecd1aac171ae8325d42a4b8",
+     "grade": false,
+     "grade_id": "cell-47f69f9819a6c7ad",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d544f60e-b75c-4b8f-a695-7b9ec7bd138b",
+   "metadata": {},
+   "source": [
+    "**Question 3.3 -** On souhaite à présent implémenter en Programmation Dynamique la limite du stock de pièces présentée pour les exercices 1.2 et 1.3. Pour ce faire on modifie la formule de $Q_{opt}$ donnée précédemment (valable ici uniquement pour $i\\geq1$) :\n",
+    "\n",
+    "$Q_{opt}(i,m) = min\n",
+    "\\begin{cases}\n",
+    "Q_{opt}(i-1, m) \\qquad \\qquad \\qquad \\qquad \\qquad \\qquad \\qquad \\text{ on n'utilise aucune pièce de type i}\\\\\n",
+    "1 + Q_{opt}(i-1, m-v_i) \\quad si\\ d_i\\geq1\\ et\\ (m-v_i) \\geq 0  \\qquad \\text{ on utilise 1 pièce de type i}\\\\\n",
+    "2 + Q_{opt}(i-1, m-2v_i) \\quad si\\ d_i\\geq2\\ et\\ (m-2v_i) \\geq 0  \\quad \\text{ on utilise 2 pièces de type i}\\\\\n",
+    "3 + Q_{opt}(i-1, m-3v_i) \\quad si\\ d_i\\geq3\\ et\\ (m-3v_i) \\geq 0  \\quad \\text{ on utilise 3 pièces de type i}\\\\\n",
+    "...\n",
+    "\\end{cases}\n",
+    "$\n",
+    "\n",
+    "Implémentez la limite de pièces avec cette nouvelle formule pour l'algorithme en Programmation Dynamique. Notez ici qu'on ne va plus chercher les valeurs sur la même ligne dans la matrice, mais qu'on remonte _systématiquement_ d'une ligne, pour qu'après l'utilisation de $k$ pièces de valeur $v_i$, on ne puisse plus ajouter d'autres pièces de cette même valeur."
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "8c05a462-3d75-48be-903c-3fa922bbd63d",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "587f7bf7d15530f0614fdb0e22ec53cb",
+     "grade": false,
+     "grade_id": "cell-440494d7b4acaaf3",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "5ee21bfb-c169-48d0-93cc-75c6be089d03",
+   "metadata": {},
+   "source": [
+    "**Question 3.4 -** On dispose à présent du poids de chaque pièce en plus de sa valeur (Table 2), et on cherche à minimiser le poids total des pièces pour atteindre la valeur M. À l'aide d'une matrice analogue à la Figure 2, trouvez le poids minimal pour atteindre la valeur M=7. Notez qu'on ne cherchera plus à minimiser le nombre de pièces utilisées, seul le critère de poids compte pour cet exercice.\n",
+    "\n",
+    "| S (valeur de chaque pièce) | P (poids de chaque pièce) |\n",
+    "|---------------------------|---------------------------|\n",
+    "| 1c                        | 2.30g                     |\n",
+    "| 2c                        | 3.06g                     |\n",
+    "| 5c                        | 3.92g                     |\n",
+    "| 10c                       | 4.10g                     |\n",
+    "| 20c                       | 5.74g                     |\n",
+    "| 50c                       | 7.80g                     |\n",
+    "| 100 (1€)                  | 7.50g                     |\n",
+    "| 200 (2€)                  | 8.50g                     |\n",
+    "| 500 (5€)                  | 0.6g                      |\n",
+    "| 1000                      | 0.7g                      |\n",
+    "| 2000                      | 0.8g                      |\n",
+    "| 5000                      | 0.9g                      |\n",
+    "| 10000                     | 1g                        |\n",
+    "<center>\n",
+    "    <i>Table 2</i>\n",
+    "</center>\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "3ecdadb6-b735-47cd-ba9e-d79abb285648",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "b2c1ce245afadceaa00693a32e74c4db",
+     "grade": false,
+     "grade_id": "cell-c7773bdcbfa433f5",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "b48169e9-ada6-4f03-a24c-28745caa99bd",
+   "metadata": {},
+   "source": [
+    "**Question 3.5 -** Implémentez à présent un algorithme de Programmation Dynamique qui calcule le poids minimal pour atteindre une valeur M. Étant donné qu'avec le système monétaire en Table 2 la minimisation du nombre de pièces minimise aussi le poids, vous pourrez tester votre algorithme avec un système plus complexe tel que donné en Table 3. Essayez par exemple avec la valeur $M=6$.\n",
+    "\n",
+    "| S (valeur de chaque pièce) | P (poids de chaque pièce) |\n",
+    "|---------------------------|---------------------------|\n",
+    "| 1c                        | 10g                       |\n",
+    "| 3c                        | 27g                       |\n",
+    "| 4c                        | 32g                       |\n",
+    "| 7c                        | 55g                       |\n",
+    "<center>\n",
+    "    <i>Table 3</i>\n",
+    "</center>"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "6e72a851-5698-4cd8-85ae-b830b8469ea9",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "8bef9747abc852b3eb30d2dd73f40101",
+     "grade": false,
+     "grade_id": "cell-12851f7f3bb0341b",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "id": "d1970f87-775a-4374-9947-2ae1cff39418",
+   "metadata": {},
+   "source": [
+    "**Question 3.6 -** On propose l'algorithme ci-dessous qui tente de résoudre le problème de façon gloutonne. Implémentez cet algorithme. Pour quelles valeurs de M ($\\leq$ 20) avec la Table 3 donne-t-il une solution différente de l'algorithme à Programmation Dynamique ?\n",
+    "\n",
+    "```\n",
+    "Fonction Poids_Gloutonne\n",
+    "Entrées : liste S, liste P, entier M\n",
+    "Sortie : poids minimal pour atteindre M\n",
+    "    Soit L la liste des tuples (Pi/Si, Si, Pi), triée croissante selon le premier \n",
+    "    élément de chaque tuple\n",
+    "    M'=M\n",
+    "    res = 0\n",
+    "    Répéter\n",
+    "        Chercher dans L le premier triplet (r, s, p) tel que s <= M'\n",
+    "        res = res + p * (M' // s)\n",
+    "        M' = M' % s\n",
+    "    Jusqu'à M' = 0\n",
+    "    res est la valeur de sortie de l'algorithme\n",
+    "Fin Poids_Gloutonne\n",
+    "```"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "b7f93bbc-c1d7-4de4-8470-961a68050d9e",
+   "metadata": {
+    "deletable": false,
+    "nbgrader": {
+     "cell_type": "code",
+     "checksum": "af9b4ce8699987e19086355021572694",
+     "grade": false,
+     "grade_id": "cell-f679a179c1b0ca7e",
+     "locked": false,
+     "schema_version": 3,
+     "solution": true,
+     "task": false
+    },
+    "tags": []
+   },
+   "outputs": [],
+   "source": [
+    "# YOUR CODE HERE\n",
+    "raise NotImplementedError()"
+   ]
+  }
+ ],
+ "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
+}