TP Python – Dates au plus tôt et au plus tard en Python
BTS SIO SISR 1re année – Mathématiques pour l'informatique – S17
Note
Comment ce TP fonctionne. Chaque exercice a un éditeur Python intégré à la page (il s'exécute dans ton navigateur, rien à installer). Avant de lancer, écris sur ta feuille ce que tu anticipes (« J'anticipe »). Puis lance et compare. Le bouton Valider exécute des tests : un test réussi ne dispense pas de comprendre pourquoi.
Un graphe valué est un dictionnaire {(origine, arrivée): valeur} ; un projet est un dictionnaire {tâche: (durée, [prédécesseurs])}.
Exercice A – Dijkstra
Écris dijkstra(arcs, source, sommets) qui renvoie (distance, predecesseur) (deux dictionnaires), puis reconstruire(predecesseur, cible) qui renvoie la liste des sommets du chemin de la source à cible. Pour « l'infini », utilise float("inf").
J'anticipe. Dans le graphe du cours, quelle valeur attends-tu pour T ? Par quels sommets passe le chemin ?
def dijkstra(arcs, source, sommets):bksl-nl inf = float("inf")bksl-nl distance = {}bksl-nl predecesseur = {}bksl-nl for v in sommets:bksl-nl distance[v] = infbksl-nl predecesseur[v] = Nonebksl-nl distance[source] = 0bksl-nl fixes = []bksl-nl while len(fixes) < len(sommets):bksl-nl x = Nonebksl-nl for v in sommets:bksl-nl if v not in fixes and (x is None or distance[v] < distance[x]):bksl-nl x = vbksl-nl if distance[x] == inf:bksl-nl breakbksl-nl fixes.append(x)bksl-nl for (a, b) in arcs:bksl-nl # À compléter : si a est x, b n'est pas fixé et distance[x] + valeur < distance[b],bksl-nl # mettre à jour distance[b] et predecesseur[b]bksl-nl passbksl-nl return (distance, predecesseur)bksl-nlbksl-nldef reconstruire(predecesseur, cible):bksl-nl chemin = [cible]bksl-nl # À compléter : remonter les prédécesseurs jusqu'à la source (prédécesseur None)bksl-nl chemin.reverse()bksl-nl return cheminbksl-nlbksl-nl
Exercice B – Dates au plus tôt
Écris dates_au_plus_tot(taches) qui renvoie un dictionnaire tâche → date au plus tôt. Tant que toutes les dates ne sont pas calculées, traite les tâches dont tous les prédécesseurs ont une date.
Je comprends. Pourquoi la boucle while s'arrête-t-elle quand le projet n'a pas de circuit ? Et sinon ?
def datespy-undaupy-undpluspy-undtot(taches):bksl-nl t = {}bksl-nl restantes = list(taches)bksl-nl while len(restantes) > 0:bksl-nl pret = Nonebksl-nl for x in restantes:bksl-nl ok = Truebksl-nl for p in taches[x][1]:bksl-nl if p not in t:bksl-nl ok = Falsebksl-nl if ok:bksl-nl pret = xbksl-nl breakbksl-nl if pret is None:bksl-nl return None # circuit : aucune tâche ne peut commencerbksl-nl date = 0bksl-nl for p in taches[pret][1]:bksl-nl pass # À compléter : date = max(date, t[p] + durée de p)bksl-nl t[pret] = datebksl-nl restantes.remove(pret)bksl-nl return tbksl-nlbksl-nl
Exercice C – Marges et chemin critique
Écris analyse(taches) qui renvoie (duree_projet, marges_totales, critiques) : la durée minimale, le dictionnaire des marges totales, et la liste triée des tâches critiques. Les dates au plus tôt sont fournies par dates_au_plus_tot.
def datespy-undaupy-undpluspy-undtot(taches):bksl-nl t = {}bksl-nl restantes = list(taches)bksl-nl while len(restantes) > 0:bksl-nl pret = Nonebksl-nl for x in restantes:bksl-nl ok = Truebksl-nl for p in taches[x][1]:bksl-nl if p not in t:bksl-nl ok = Falsebksl-nl if ok:bksl-nl pret = xbksl-nl breakbksl-nl if pret is None:bksl-nl return Nonebksl-nl date = 0bksl-nl for p in taches[pret][1]:bksl-nl if t[p] + taches[p][0] > date:bksl-nl date = t[p] + taches[p][0]bksl-nl t[pret] = datebksl-nl restantes.remove(pret)bksl-nl return tbksl-nlbksl-nldef analyse(taches):bksl-nl """Renvoie (durée du projet, marges totales, liste triée des tâches critiques)."""bksl-nl t = datespy-undaupy-undpluspy-undtot(taches)bksl-nl duree = 0bksl-nl for x in taches:bksl-nl pass # À compléter : durée = max de (t[x] + durée de x)bksl-nl successeurs = {}bksl-nl for x in taches:bksl-nl successeurs[x] = []bksl-nl for x in taches:bksl-nl for p in taches[x][1]:bksl-nl successeurs[p].append(x)bksl-nl tard = {}bksl-nl restantes = list(taches)bksl-nl tours = 0bksl-nl while len(restantes) > 0 and tours < 100:bksl-nl tours = tours + 1bksl-nl for x in restantes:bksl-nl if all(s in tard for s in successeurs[x]):bksl-nl fin = dureebksl-nl for s in successeurs[x]:bksl-nl pass # À compléter : fin = le plus petit des tard[s]bksl-nl tard[x] = fin - taches[x][0]bksl-nl restantes.remove(x)bksl-nl breakbksl-nl marges = {}bksl-nl for x in taches:bksl-nl marges[x] = 0 # À compléter : tard[x] - t[x]bksl-nl critiques = [] # À compléter : tâches de marge nulle, triéesbksl-nl return (duree, marges, critiques)bksl-nlbksl-nl