{ "cells": [ { "cell_type": "markdown", "metadata": { "toc": "true" }, "source": [ "# Table of Contents\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Texte d'oral de modélisation - Agrégation Option Informatique\n", "## Préparation à l'agrégation - ENS de Rennes, 2016-17\n", "- *Date* : 22 mai 2017\n", "- *Auteur* : [Lilian Besson](https://GitHub.com/Naereen/notebooks/)\n", "- *Texte*: Annale 2012, [\"Éclairage graphe\" (public2012-D1)](http://agreg.org/Textes/public2012-D1.pdf)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## À propos de ce document\n", "- Ceci est une *proposition* de correction, partielle et probablement non-optimale, pour la partie implémentation d'un [texte d'annale de l'agrégation de mathématiques, option informatique](http://Agreg.org/Textes/).\n", "- Ce document est un [notebook Jupyter](https://www.Jupyter.org/), et [est open-source sous Licence MIT sur GitHub](https://github.com/Naereen/notebooks/tree/master/agreg/), comme les autres solutions de textes de modélisation que [j](https://GitHub.com/Naereen)'ai écrite cette année.\n", "- L'implémentation sera faite en OCaml, version 4+ :" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The OCaml toplevel, version 4.04.2\n" ] }, { "data": { "text/plain": [ "- : int = 0\n" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "Sys.command \"ocaml -version\";;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----\n", "## Question de programmation\n", "La question de programmation pour ce texte était donnée au tout début, à la page 2 :\n", "\n", "### Exercice\n", "\n", "> Dans le langage de votre choix, implémenter un programme qui étant donnés un graphe et une proposition d’éclairage des lampadaires teste si celle-ci est correcte, *i.e.*, si toutes les rues sont bien éclairées.\n", "\n", "> Le tester sur différents exemples bien choisis (on pourra justifier la/les structures de données utilisée).\n", "\n", "### Besoin de plusieurs exemples\n", "Pour une fois, on voit bien que le jury *exige* de tester la fonction sur *plusieurs* exemples." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "----\n", "## Solution\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Représentation du graphe et de la proposition d'éclairage\n", "\n", "Les graphes ici seront constitués de *places* (= sommets), reliés entre elles par des *rues* (= arêtes).\n", "\n", "Pour vérifier un éclairage, donné sous forme d'une liste de places, on va devoir vérifier que chaque rue est connectée à une place éclairée.\n", "\n", "Une approche très simple, en trois étapes :\n", "\n", "1. compter le nombre de rues,\n", "2. pour chaque place éclairée, compter le nombre de rues qui en partent (et qui sont donc éclairées),\n", "3. s'il y a (au moins) une rue non éclairée, renvoyer `false`, sinon renvoyer `true`.\n", "\n", "Pour être efficace, il faut pouvoir accéder efficacement aux rues qui partent de chaque place (et il suffit de les compter, si on sait qu'elles sont uniques dans la représentation).\n", "\n", "$\\implies$ À partir de ce constat, on opte pour une représentation du graphe par **liste d'adjacence**.\n", "\n", "- Comme les graphes sont non orientés, chaque arête est présente deux fois dans la représentation du graphe : l'arête $u \\leftrightarrow v$ est présente comme $v \\in V[u]$ (les places voisines de $u$), et $u \\in V[v]$ (les places voisines de $v$).\n", "\n", "- Le fait que les graphes soient planaires n'apportent rien à la représentation.\n", "\n", "- Par simplicité, on va représenter les places par leur numéros (on pourra aussi prendre des chaînes de caractères, comme `\"Place de l'étoile\"`, `\"Nation\"`, `\"Champd de Mars\"` etc, mais c'est plus long à écrire)." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "type place = int\n" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "type rues = place list\n" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type place = int;;\n", "type rues = place list;;" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "type ville = rues list\n" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type ville = rues list;;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On donne tout de suite un exemple de graphe, en prenant le 3ème exemple de la Figure 1 du texte.\n", "\n", "![Graphes de la Figure 1 du texte](images/ville_eclairee_1.png)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "val graphe1 : ville =\n", " [[2]; [2; 3; 6]; [0; 1]; [1; 4]; [3; 5]; [1; 4; 6; 8]; [1; 5; 7]; [6; 8];\n", " [5; 7]]\n" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let graphe1 : ville = [\n", " [2]; (* place 0 *)\n", " [2; 3; 6]; (* place 1 *)\n", " [0; 1]; (* place 2 *)\n", " [1; 4]; (* place 3 *)\n", " [3; 5]; (* place 4 *)\n", " [1; 4; 6; 8]; (* place 5 *)\n", " [1; 5; 7]; (* place 6 *)\n", " [6; 8]; (* place 7 *)\n", " [5; 7]; (* place 8 *)\n", "];;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On a besoin que les indices commence à $0$ et jusqu'à $n-1$ (où $n$ est le nombre de places), puisque la liste des rues utilisent implicitement la numérotation des places." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "type eclairage = place list\n" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type eclairage = place list;;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Trois exemples d'éclairages, deux satisfaisant donc l'un trivialement, et l'autre non satisfaisant :" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "val eclairage1_sat : eclairage = [0; 1; 2; 3; 4; 5; 6; 7; 8]\n" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "val eclairage2_sat : eclairage = [1; 2; 3; 5; 6; 8]\n" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let eclairage1_sat : eclairage = [\n", " 0; 1; 2; 3; 4; 5; 6; 7; 8\n", "];;\n", "\n", "let eclairage2_sat : eclairage = [\n", " 1; 2; 3; 5; 6; 8\n", "];;" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "val eclairage1_nonsat : eclairage = [2; 4; 8]\n" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" }, { "data": { "text/plain": [ "val eclairage2_nonsat : eclairage = [1; 2; 3; 5; 6]\n" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "let eclairage1_nonsat : eclairage = [\n", " 2; 4; 8\n", "];;\n", "\n", "let eclairage2_nonsat : eclairage = [\n", " 1; 2; 3; 5; 6\n", "];;" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Vérification\n", "\n", "On pourrait écrire une première fonction pour vérifier que le graphe est bien valide, selon la représentation décrite ci-dessus, en vérifiant :\n", "- que les places forment bien l'ensemble $\\{0,\\dots,n-1\\}$,\n", "- que chaque rue n'est présente qu'une fois dans les listes d'adjacences $V[u]$,\n", "- qu'aucune place inconnue n'est dans une liste $V[u]$,\n", "- et que le graphe est bien symétrique non-orienté, i.e., que $u \\in V[u] \\Leftrightarrow v \\in V[u]$.\n", "\n", "... Mais le sujet n'exige rien de tout ça, donc on passe directement à la question demandée." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Quelques fonctions utiles :" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "val somme : int list -> int =