420 lines
84 KiB
Plaintext
420 lines
84 KiB
Plaintext
|
|
{
|
|||
|
|
"cells": [
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"# Calcul du chemin le plus court"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"source": "## Séance 6 (1/2) — Graphes pondérés et algorithme de Dijkstra : recap force brute\n\nJusqu'ici, nos graphes indiquaient seulement l'existence d'un lien entre deux individus (Séances 2 et 3). Mais en sociologie, toutes les relations ne se valent pas : deux personnes peuvent se croiser une fois par an ou se parler tous les jours. On peut représenter cette **intensité** par un **poids** sur chaque arête (voir FONDAMENTAUX.md, §2.3) — par exemple le temps qu'il faut pour transmettre une information d'une personne à l'autre, ou l'inverse de la fréquence de contact.\n\n**Question sociologique posée par cette séance :** dans un réseau où chaque lien a un coût (temps, distance, effort), quel est le chemin le *moins coûteux* entre deux individus ? C'est exactement le problème que résout l'**algorithme de Dijkstra**, que nous découvrirons juste après cette activité de recap (méthode \"force brute\").\n\nL'exercice ci-dessous l'illustre sur un cas logistique concret (circuits courts en Bretagne) : le raisonnement — trouver le chemin de poids minimal dans un graphe pondéré — est rigoureusement le même que pour calculer, par exemple, le canal de diffusion le plus rapide d'une information dans un réseau social pondéré par la force des liens.\n\n> Pour aller plus loin : la preuve formelle de l'algorithme de Dijkstra (terminaison, invariant de boucle) et l'analyse de sa complexité sont regroupées dans une **annexe optionnelle** (`Annexe_Dijkstra_Preuve_Complexite.ipynb`), à explorer si vous êtes à l'aise et que le temps le permet.",
|
|||
|
|
"metadata": {}
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"## Introduction"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"Lors de cette activité, vous allez travailler sur un algorithme permettant la détermination du chemin le plus court entre deux points d'un graphe. Vous allez réinvestir vos notions de programmation et d'algorithme (définition, correction et optimisation)."
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"## Énoncé"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"attachments": {
|
|||
|
|
"graphe.png": {
|
|||
|
|
"image/png": "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
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"Un site web propose une plateforme reliant producteurs et consommateurs en Bretagne. Leur objectif étant de proposer des circuits courts et ainsi de contribuer au développement écologique et économique de la région. \n",
|
|||
|
|
" Afin d’aider les consommateurs a préparer leurs courses, les responsables du site web souhaitent développer un algorithme qui optimise leur trajet pour l’achat des différent vivres. \n",
|
|||
|
|
" En cochant les cases des produits que le consommateur souhaite acheter (fruits, légumes, produits carnés, produits laitiers, produits de la pêche,…) l’algorithme proposera le chemin le plus court pour faire l’ensemble des achats. \n",
|
|||
|
|
" Regardons l’exemple ci-dessous :\n",
|
|||
|
|
"\n"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"### Question 1\n",
|
|||
|
|
"Rechercher le chemin le plus court entre le point A et le point G. Notez les différentes étapes, ainsi que la distance parcouru en total."
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"On représente ce graphe dans un premier temps sous forme de tableau:\n",
|
|||
|
|
" | | A | B | C | D | E | F | G | H |\n",
|
|||
|
|
"|:- |:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|\n",
|
|||
|
|
"|A|0|4|2|-|-|-|-|-|\n",
|
|||
|
|
"|B|4|0|6|-|5|-|-|-|\n",
|
|||
|
|
"|C|2|6|0|3|-|-|-|5|\n",
|
|||
|
|
"|D|-|-|3|0|-|3|4|1|\n",
|
|||
|
|
"|E|-|5|-|-|0|2|-|-|\n",
|
|||
|
|
"|F|-|-|-|3|2|0|7|-|\n",
|
|||
|
|
"|G|-|-|-|4|-|7|0|10|\n",
|
|||
|
|
"|H|-|-|5|1|-|-|10|0|\n",
|
|||
|
|
" Puis on décide de modéliser ce graphe sous Python à l'aide d'une liste de listes:"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": null,
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"# Déclaration de notre graphe sous forme de liste de liste\n",
|
|||
|
|
"graphe = [\n",
|
|||
|
|
" [0 ,4 ,2 ,99,99,99,99,99],\n",
|
|||
|
|
" [4 ,0 ,6 ,99,5 ,99,99,99],\n",
|
|||
|
|
" [2 ,6 ,0 ,3 ,99,99,5 ,99],\n",
|
|||
|
|
" [99,99,3 ,0 ,99,3 ,4 ,1 ],\n",
|
|||
|
|
" [99,5 ,99,99,0 ,2 ,99,99],\n",
|
|||
|
|
" [99,99,99,3 ,2 ,0 ,7 ,99],\n",
|
|||
|
|
" [99,99,99,4 ,99,7 ,0 ,10],\n",
|
|||
|
|
" [99,99,5 ,1 ,99,99,10,0 ]\n",
|
|||
|
|
"]\n",
|
|||
|
|
"\n",
|
|||
|
|
"graphe # Vérification de notre sortie"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"### Question 2:"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
" 1. Quel choix a fait le développeur pour indiquer la non existence d'un arc entre deux sommets ?\n",
|
|||
|
|
" 2. Ce choix vous semble t-il judicieux ? Argumentez.\n",
|
|||
|
|
" 3. Que proposeriez-vous au développeur ? "
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"## Calcul de la distance entre deux sommets"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"Le calcul de la distance entre deux noeuds se fait à l'aide d'une fonction intitulé <b>distance</b> dont le code est donne ci dessous:"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": null,
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"def distance(départ, arrivée) -> int:\n",
|
|||
|
|
" # on vérifie que les valeurs de départ et arrivée sont bien des entiers\n",
|
|||
|
|
" assert type(départ) == int, \"la valeur départ n'est pas un entier\"\n",
|
|||
|
|
" assert type(arrivée) == int, \"la valeur départ n'est pas un entier\"\n",
|
|||
|
|
" assert graphe[départ][arrivée] != 99, \"les noeuds ne sont pas adjacent\"\n",
|
|||
|
|
" \n",
|
|||
|
|
" return(graphe[départ][arrivée])"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"### Question 3"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
" 1. Que renvoie l'instruction $distance(2,3)$ ?\n",
|
|||
|
|
" 1. 6\n",
|
|||
|
|
" 2. \"La valeur n'est pas un entier\"\n",
|
|||
|
|
" 3. 3\n",
|
|||
|
|
" 4. 99\n",
|
|||
|
|
" 2. Démonstration de la correction de cette fonction. \n",
|
|||
|
|
" - Dans un premier temps montrez que la fonction se termine (pour rappel cela consiste a verifier que les calculs effectuées par l'algorithme s'arretent bien):\n",
|
|||
|
|
" 1. Il n'y a aucune boucle dans la fonction, elle se termine forcément\n",
|
|||
|
|
" 2. La fonction ne vérifie pas tout les cas possibles, elle ne se termine jamais dans certains cas\n",
|
|||
|
|
" 3. Une fonction ne se termine que lorsqu'il y a une boucle \"while\"\n",
|
|||
|
|
" - Dans un deuxieme temps montrer la correction partielle (pour rappel: l'algorithme donne bien le bon résultat)\n",
|
|||
|
|
" 1. Pour chaque couple de sommets la fonction retourne bien la distance demandée\n",
|
|||
|
|
" 2. Le développeur n'a pas prévu le cas où l'on passe le même sommet en arrivée et départ\n",
|
|||
|
|
" 3. L'algorithme ne donne pas le bon résultat.\n",
|
|||
|
|
" 3. Quel est le niveau de complexité de cette fonction ? QCM\n",
|
|||
|
|
" 1. Il s'agit du parcours séquentiel d'un tableau, $n \\log(n)$\n",
|
|||
|
|
" 2. $1$\n",
|
|||
|
|
" 3. $n^2$\n",
|
|||
|
|
" 4. $0$"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"## Création d'une liste de sommets adjacents"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"Maintenant que nous savons déterminer la distance entre deux noeuds, on a besoin de connaitre les différents parcours entre un point de départ et un point d'arrivée. On crée d'abord une fonction qui retourne la liste des noeuds adjacents par rapport a un noeud de référence."
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": null,
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"def determine_adjacents(sommet) -> list:\n",
|
|||
|
|
" #************************************************************************\n",
|
|||
|
|
" # A partir d'un noeud en entrée, la fonction donne la liste des noeuds adjacents\n",
|
|||
|
|
" # Entrée : Le noeud de départ\n",
|
|||
|
|
" # Sortie : la liste des noeuds adjacents\n",
|
|||
|
|
" #************************************************************************\n",
|
|||
|
|
" # On sélectionne la ligne contenant les noeuds adjacent par rapport a notre point de départ\n",
|
|||
|
|
" ligne = graphe[sommet]\n",
|
|||
|
|
"\n",
|
|||
|
|
" # on détermine le nombre de noeuds adjacents pour ce point\n",
|
|||
|
|
" nb_adjacent = len(ligne)-ligne.count(99)-ligne.count(0)\n",
|
|||
|
|
"\n",
|
|||
|
|
" # Puis on crée la variable parcours sous forme de liste de listes\n",
|
|||
|
|
" liste_adjacents = [[] for i in range(0,nb_adjacent)]\n",
|
|||
|
|
"\n",
|
|||
|
|
" a = 0\n",
|
|||
|
|
" for i in range(0,len(ligne)):\n",
|
|||
|
|
" if (ligne[i] != 0 and ligne[i] != 99):\n",
|
|||
|
|
" liste_adjacents[a].append(sommet)\n",
|
|||
|
|
" liste_adjacents[a].append(i)\n",
|
|||
|
|
" a += 1\n",
|
|||
|
|
" \n",
|
|||
|
|
" # On retourne la liste des sommet adjacents\n",
|
|||
|
|
" return(liste_adjacents)\n",
|
|||
|
|
"\n",
|
|||
|
|
"#****************************************************************************\n",
|
|||
|
|
"# Ajouter votre code ici pour l'exécution de la fonction ci-dessous"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"### Question 4"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
" 1. Faites fonctionner la fonction $determine$_$adjacents$ pour l'ensemble des sommets du graphe, imprimez le résultat.\n",
|
|||
|
|
" 2. Vérifier qu'il n'y ait pas d'erreur dans la transcription du graph. Le corriger le cas échéant."
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"## Composition d'une liste de listes avec l'ensemble des chemins possibles entre un point de départ et un point d'arrivée."
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"Pour commencer cette exercice, nous allons d'abord nous intéresser au nombre de noeuds adjacents par rapport a notre point de départ, puis, à partir de cette liste, nous allons bâtir l'ensemble des chemins possibles."
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": null,
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"def recursive2(liste) -> list:\n",
|
|||
|
|
" #************************************************************************\n",
|
|||
|
|
" # La fonction récursive établit la liste exhaustive des chemins possibles\n",
|
|||
|
|
" # Entrée : La liste de chemins déja établie\n",
|
|||
|
|
" # Sortie : la liste de chemins jusqu'au noeuds suivants\n",
|
|||
|
|
" #************************************************************************\n",
|
|||
|
|
" \n",
|
|||
|
|
" sommets_adjacents = []\n",
|
|||
|
|
" # On détermine le nombre d'arcs adjacents aux noeuds\n",
|
|||
|
|
" for i in range(0,len(liste)): # on boucle dans notre liste existante\n",
|
|||
|
|
" for element in determine_adjacents(liste[i][-1]): # pour chaque sommet dans la liste des adjacents\n",
|
|||
|
|
" if element not in sommets_adjacents: # si le sommet n'est pas encore dans notre liste\n",
|
|||
|
|
" sommets_adjacents.append(element) # alors on le rajoute\n",
|
|||
|
|
" \n",
|
|||
|
|
" # On identifie les chemins qu'on doit créer, en ignorant les chemins:\n",
|
|||
|
|
" # - où on revient sur un noeud déja visité\n",
|
|||
|
|
" # - déja existant dans la liste\n",
|
|||
|
|
" # Puis on renseigne les chemins possibles\n",
|
|||
|
|
"\n",
|
|||
|
|
" entrees_a_supprimer = [] # On va garder en mémoire les entrées a supprimer\n",
|
|||
|
|
" for i in range(0,len(liste)) : # on boucle dans notre liste existante\n",
|
|||
|
|
" if liste[i][-1] != arrivée: # on ignore les chemins menant déja au point d'arrivée\n",
|
|||
|
|
" for j in range(0,len(sommets_adjacents)): # on boucle dans la liste qu'on vient d'obtenir\n",
|
|||
|
|
" if (sommets_adjacents[j][0] == liste[i][-1] and\n",
|
|||
|
|
" sommets_adjacents[j][-1] != liste[i][0] and\n",
|
|||
|
|
" sommets_adjacents[j][-1] not in liste[i]\n",
|
|||
|
|
" ):\n",
|
|||
|
|
" liste.append(liste[i] + sommets_adjacents[j][1:len(sommets_adjacents)])\n",
|
|||
|
|
" entrees_a_supprimer.append(i) # On va garder en mémoire les entrées a supprimer\n",
|
|||
|
|
" \n",
|
|||
|
|
" for i in range(0,len(entrees_a_supprimer)): # avant de retourner notre résultat on supprime les entrées superflus\n",
|
|||
|
|
" del liste[entrees_a_supprimer[i]-i]\n",
|
|||
|
|
" return(liste)"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"### Question 5"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"En étudiant la fonction $recursive2$ ci-dessus, répondez aux questions suivantes:\n",
|
|||
|
|
" 1. Identifier la ligne de code qui ajoute les chemins possible a la liste.\n",
|
|||
|
|
" 2. Ecrivez le commentaire de cette ligne de code en langage naturel ou pseudocode.\n",
|
|||
|
|
" 3. Quel est le coût de cette fonction ?\n",
|
|||
|
|
" 1. Il s'agit du parcours séquentiel d'un tableau, le coût est linéaire ;\n",
|
|||
|
|
" 2. Il s'agit d'un tri par insertion, au pire le coût de cette fonction est quadratique ($n^2$) ;\n",
|
|||
|
|
" 3. Il s'agit d'un succession d'instructions simple, le cout est de 1."
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"## Programme principal"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": null,
|
|||
|
|
"metadata": {
|
|||
|
|
"scrolled": true
|
|||
|
|
},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": "#************************************************************************\n# Transcription du graphe sous forme de liste de listes\n#************************************************************************\n\ngraphe = [\n [0 ,4 ,2 ,99,99,99,99,99],\n [4 ,0 ,6 ,99,5 ,99,99,99],\n [2 ,6 ,0 ,3 ,99,99,5 ,99],\n [99,99,3 ,0 ,99,3 ,4 ,1 ],\n [99,5 ,99,99,0 ,2 ,99,99],\n [99,99,99,3 ,2 ,0 ,7 ,99],\n [99,99,99,4 ,99,7 ,0 ,10],\n [99,99,5 ,1 ,99,99,10,0 ]\n ]\n\ndef distance(Noeud_A, Noeud_B) -> int:\n #************************************************************************\n # Donne la distance entre deux noeuds adjacents Noeud_A et Noeud_B\n # Entrée : Le noeud de départ\n # Sortie : la liste des noeuds adjacents\n #************************************************************************\n # on vérifie que les valeurs de départ et arrivée sont bien des entiers\n assert type(Noeud_A) == int, \"la valeur départ n'est pas un entier\"\n assert type(Noeud_B) == int, \"la valeur départ n'est pas un entier\"\n assert graphe[Noeud_A][Noeud_B] != 99, \"les noeuds ne sont pas adjacent\"\n \n # On retourne la distance entre les deux noeuds\n return(graphe[Noeud_A][Noeud_B])\n\n\ndef determine_adjacents(noeud) -> list:\n #************************************************************************\n # A partir d'un noeud en entrée, la fonction donne la liste des noeuds adjacents\n # Entrée : Le noeud de départ\n # Sortie : la liste des noeuds adjacents\n #************************************************************************\n # On sélectionne la ligne contenant les noeuds adjacent par rapport a notre point de départ\n ligne = graphe[noeud]\n\n # on détermine le nombre de noeuds adjacents pour ce point\n nb_adjacent = len(ligne)-ligne.count(99)-ligne.count(0)\n\n # Puis on crée la variable parcours sous forme de liste de listes\n liste_adjacents = [[] for i in range(0,nb_adjacent)]\n\n a = 0\n for i in range(0,len(ligne)):\n if (ligne[i] != 0 and ligne[i] != 99):\n liste_adjacents[a].append(noeud)\n liste_adjacents[a].append(i)\n a += 1\n \n # On retourne la liste des noeuds adjacents\n return(liste_adjacents)\n\ndef recursive2(liste) -> list:\n #************************************************************************\n # La fonction récursive établit la liste exhaustive des chemins possibles\n # Entrée : La liste de chemins déja établie\n # Sortie : la liste de chemins jusqu'au noeuds suivants\n #************************************************************************\n \n sommets_adjacents = []\n # On détermine le nombre d'arcs adjacents aux noeuds\n for i in range(0,len(liste)): # on boucle dans notre liste existante\n for element in determine_adjacents(liste[i][-1]): # pour chaque sommet dans la liste des adjacents\n if element not in sommets_adjacents: # si le sommets n'est pas encore dans notre liste\n sommets_adjacents.append(element) # alors on le rajoute\n \n # On identifie les chemins qu'on doit créer, en ignorant les chemins:\n # - où on revient sur un noeud déja visité\n # - déja existant dans la liste\n # Puis on renseigne les chemins possibles\n\n entrees_a_supprimer = [] # On va garder en mémoire les entrées a supprimer\n for i in range(0,len(liste)) : # on boucle dans notre liste existante\n if liste[i][-1] != arrivée: # on ignore les chemins menant déja au point d'arrivée\n for j in range(0,len(sommets_adjacents)): # on boucle dans la liste qu'on vient d'obtenir\n if (sommets_adjacents[j][0] == liste[i][-1] and\n sommets_adjacents[j][-1] != liste[i][0] and\n sommets_adjacents[j][-1] not in liste[i]\n ):\n liste.append(liste[i] + somm
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"### Question 6"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "markdown",
|
|||
|
|
"metadata": {},
|
|||
|
|
"source": [
|
|||
|
|
"1. Le programme ci dessous n'affiche pas le résultat attendu. Modifiez le pour qu'on vous affiche le chemin le plus court, et la distance a parcourir.\n",
|
|||
|
|
"2. Implementez la fonction $timeit$ et $memit$ afin de connaître le temps d'exécution et la mémoire occupé par la fonction \"recursive2\"\n",
|
|||
|
|
"3. Est-ce que les résultats confirment votre réponse à la question 5.3 ?"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": null,
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"pip install memory_profiler"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": null,
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"%load_ext memory_profiler"
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
{
|
|||
|
|
"cell_type": "code",
|
|||
|
|
"execution_count": null,
|
|||
|
|
"metadata": {},
|
|||
|
|
"outputs": [],
|
|||
|
|
"source": [
|
|||
|
|
"# Déclaration des variables en fonction des itérations\n",
|
|||
|
|
"chemins_it1 = [[0, 1], [0, 2]]\n",
|
|||
|
|
"chemins_it3 = [[0, 1, 2, 3], [0, 1, 2, 7], [0, 1, 4, 5], [0, 2, 1, 4], [0, 2, 3, 5], [0, 2, 3, 6], [0, 2, 3, 7], [0, 2, 7, 3], [0, 2, 7, 6]]\n",
|
|||
|
|
"chemins_it5 = [[0, 2, 3, 6], [0, 2, 7, 6], [0, 1, 2, 3, 6], [0, 1, 2, 7, 6], [0, 1, 4, 5, 6], [0, 2, 3, 5, 6], [0, 2, 3, 7, 6], [0, 2, 7, 3, 6], [0, 1, 2, 3, 5, 4], [0, 1, 2, 3, 5, 6], [0, 1, 2, 3, 7, 6], [0, 1, 2, 7, 3, 5], [0, 1, 2, 7, 3, 6], [0, 1, 4, 5, 3, 2], [0, 1, 4, 5, 3, 6], [0, 1, 4, 5, 3, 7], [0, 2, 1, 4, 5, 3], [0, 2, 1, 4, 5, 6], [0, 2, 3, 5, 4, 1], [0, 2, 7, 3, 5, 4], [0, 2, 7, 3, 5, 6]]\n",
|
|||
|
|
" \n",
|
|||
|
|
"# Time and memory Profile\n",
|
|||
|
|
"# # Ecrivez votre réponse à la question 6.2 ici"
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"metadata": {
|
|||
|
|
"kernelspec": {
|
|||
|
|
"display_name": "Python 3",
|
|||
|
|
"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.7.6"
|
|||
|
|
},
|
|||
|
|
"latex_envs": {
|
|||
|
|
"LaTeX_envs_menu_present": true,
|
|||
|
|
"autoclose": false,
|
|||
|
|
"autocomplete": true,
|
|||
|
|
"bibliofile": "biblio.bib",
|
|||
|
|
"cite_by": "apalike",
|
|||
|
|
"current_citInitial": 1,
|
|||
|
|
"eqLabelWithNumbers": true,
|
|||
|
|
"eqNumInitial": 1,
|
|||
|
|
"hotkeys": {
|
|||
|
|
"equation": "Ctrl-E",
|
|||
|
|
"itemize": "Ctrl-I"
|
|||
|
|
},
|
|||
|
|
"labels_anchors": false,
|
|||
|
|
"latex_user_defs": false,
|
|||
|
|
"report_style_numbering": false,
|
|||
|
|
"user_envs_cfg": false
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
"nbformat": 4,
|
|||
|
|
"nbformat_minor": 4
|
|||
|
|
}
|