Un corrigé pédagogique pour comprendre et justifier vos réponses. Les conseils de rédaction ne constituent pas un barème officiel détaillé.
Exercice 1 · 6 points
Réseau multisite et capacité d’une table de routage
Une entreprise interconnecte trois sites avec cinq routeurs. Le site A comporte les PC A01 et A02 reliés au switch A, connecté à R1. Le site B comporte B01, B02, B03, reliés au switch B et à R2. Le site C comporte C01, C02, reliés au switch C et à R4. Voici toutes les liaisons entre les routeurs :
Lire les connexions du schéma
- R1 relié à R3
- R1 relié à R4
- R2 relié à R3
- R5 relié à R4
- R3 relié à R4
- R5 relié à R2
RIP minimise le nombre de sauts entre routeurs. OSPF minimise la somme des coûts des liaisons, avec la formule imposée coût = 10⁸ / débit, où le débit est en bit/s et le coût sans unité. La configuration IP, les masques, les routes, la mémoire et les tables de routage doivent être cohérents.
Une IPv4 IP/S comporte quatre octets de 0 à 255. Les S premiers bits identifient le réseau, les autres la machine. L’adresse réseau a tous ses bits machine à 0 ; l’adresse de diffusion les a tous à 1. Ces deux adresses sont réservées. PC C01 possède 172.16.2.1/16.
Question 1
#Déterminer l’adresse du réseau local du site C.
Indice
16 bits correspondent exactement à deux octets.
Comprendre la correction
172.16.0.0. Le /16 fixe les deux premiers octets ; les seize bits restants deviennent 0 pour l’adresse réseau. Il ne faut pas conserver le 2 du troisième octet : il appartient ici à la partie machine.
Question 2
#Déterminer l’adresse de diffusion du site C.
Indice
Conservez la partie réseau et mettez tous les bits machine à 1.
Comprendre la correction
172.16.255.255. Les deux octets de la partie machine sont remplis de bits à 1, soit 255 pour chacun.
Question 3
#Combien de machines au maximum peut-on connecter au réseau local du site C, machines déjà présentes comprises ?
Indice
Comptez les bits variables puis retirez les deux adresses réservées.
Comprendre la correction
2¹⁶ - 2 = 65 534 adresses hôtes utilisables. On enlève le réseau et la diffusion. Le nombre demandé est une capacité totale, pas une capacité restante après décompte des machines dessinées.
| Destination | Passe par | Nombre de sauts |
|---|---|---|
| R2 | À compléter | À compléter |
| R3 | À compléter | À compléter |
| R4 | À compléter | À compléter |
| R5 | À compléter | À compléter |
Question 4
#Compléter la table RIP de R1 : destination, prochain routeur (« Passe par ») et nombre de sauts.
Indice
Explorez d’abord les voisins de R1 puis leurs voisins.
Comprendre la correction
| Destination | Passe par | Sauts |
|---|---|---|
| R2 | R3 | 2 |
| R3 | R3 | 1 |
| R4 | R4 | 1 |
| R5 | R4 | 2 |
Pour chaque destination, la colonne « Passe par » contient le premier routeur après R1, pas la route entière. Les voisins directs ont un coût de 1.
Question 5
#Quel chemin suit un paquet de PC A01 vers PC B01 avec RIP ?
Indice
Cherchez la route la plus courte entre R1 et R2.
Comprendre la correction
PC A01 → switch A → R1 → R3 → R2 → switch B → PC B01. La portion de routage utilise deux sauts : R1-R3 et R3-R2. Les commutateurs locaux ne s’ajoutent pas à la métrique RIP définie ici.
Question 6
#R3 tombe en panne. Quelle nouvelle route RIP peut relier R1 à R2 ?
Indice
Écartez R3 et tous les trajets qui le traversent.
Comprendre la correction
R1 → R4 → R5 → R2, soit trois sauts. Une panne de routeur supprime toutes ses liaisons, et pas seulement une arête.
Question 7
#Compléter les coûts OSPF pour Ethernet (10⁷ bit/s), Fast Ethernet (10⁸ bit/s) et fibre (10⁹ bit/s).
Indice
Diviser des puissances de 10 revient à soustraire leurs exposants.
Comprendre la correction
| Connexion | Calcul | Coût |
|---|---|---|
| Ethernet | 10⁸ / 10⁷ | 10 |
| Fast Ethernet | 10⁸ / 10⁸ | 1 |
| Fibre | 10⁸ / 10⁹ | 0,1 |
On applique exactement la formule donnée, y compris le coût fractionnaire de la fibre. Aucune règle d’arrondi d’un équipement réel n’est à ajouter au modèle du sujet.
| Liaison | Connexion |
|---|---|
| R1-R3 | Fibre |
| R1-R4 | Ethernet |
| R2-R3 | Ethernet |
| R5-R4 | Fast Ethernet |
| R3-R4 | Fast Ethernet |
| R5-R2 | Fast Ethernet |
Question 8
#Déterminer et justifier la route OSPF entre R1 et R4.
Indice
Le coût total s’additionne ; le nombre de liens seul ne décide pas.
Comprendre la correction
R1 → R3 → R4 coûte 0,1 + 1 = 1,1, contre 10 pour la liaison directe R1-R4. Le détour par R3-R2-R5-R4 coûterait 0,1 + 10 + 1 + 1 = 12,1. Le protocole choisit donc deux liens rapides plutôt qu’un seul lien lent.
Un routeur est une chaîne, par exemple R1, et une route une liste de routeurs, par exemple ["R1", "R3", "R2"]. On propose :
liste_routes = []
MAX_ROUTES = 5
def ajouter_route(route):
liste_routes.append(route)Question 9
#Pourquoi ce code ne garantit-il pas la limite du nombre de routes ?
Indice
Cherchez où la valeur MAX_ROUTES est utilisée après son affectation.
Comprendre la correction
MAX_ROUTES reçoit 5, mais cette constante n’intervient jamais dans la fonction. Chaque appel à append ajoute une route, y compris la sixième et les suivantes. Donner un nom à une limite n’impose pas automatiquement la contrainte : il faut la tester avant la modification.
La classe possède un entier capacite, égal à 5 par défaut, et une liste routes. Sa méthode ajouter refuse l’insertion quand la limite est atteinte et affiche alors un message.
class Routage:
def __init__(self, capacite=5):
self.capacite = ...
self.routes = []
def ajouter(self, route):
if ...:
...
else:
...Question 10
#Compléter les lignes 3, 7, 8 et 10 de la classe Routage.
Indice
On compare la longueur actuelle à la capacité avant append.
Comprendre la correction
class Routage:
def __init__(self, capacite=5):
self.capacite = capacite
self.routes = []
def ajouter(self, route):
if len(self.routes) < self.capacite:
self.routes.append(route)
else:
print("Capacité maximale atteinte")La capacité fournie au constructeur est conservée dans l’instance. L’inégalité doit être stricte : si la liste contient déjà cinq routes pour une capacité de cinq, aucun nouvel ajout ne doit avoir lieu. Chaque instance possède sa propre liste.
On peut vérifier la borne avec une instance de capacité1 : le premier ajout laisse une route dans la liste ; le second doit conserver cette même longueur et produire le message de refus. Avec deux instances, un ajout dans l’une ne doit pas modifier les routes de l’autre. Ces tests contrôlent la contrainte et l’indépendance de l’état, pas seulement l’affichage.
Pour les routes ["R1", "R3", "R2"] et ["R1", "R4", "R5", "R2"], l’affichage attendu est :
R1
R3
R2
---
R1
R4
R5
R2
---Question 11
#Écrire afficher, qui affiche chaque route, avec un routeur par ligne et --- après chaque route.
Indice
L’indentation du séparateur est la partie essentielle.
Comprendre la correction
def afficher(self):
for route in self.routes:
for routeur in route:
print(routeur)
print("---")La boucle externe choisit une route ; la boucle interne affiche ses routeurs. Le séparateur est dans la boucle externe mais en dehors de la boucle interne, donc il apparaît une seule fois par route.
Une route courte peut-elle être la plus lente ?Un atelier pour expérimenter
Sélectionnez la métrique et une panne éventuelle de R3. Le modèle recalcule les routes accessibles de R1 à R2 et montre leurs coûts.
Lire le résultat de l’expérience initiale
Route retenue : R1 → R3 → R2
Les chemins sont comparés avec la métrique choisie. Les liaisons des postes aux commutateurs et routeurs ne sont pas comptées ici.
| Route | Coût |
|---|---|
| R1 → R3 → R2 | 2 |
| R1 → R4 → R5 → R2 | 3 |
| R1 → R4 → R3 → R2 | 3 |
| R1 → R3 → R4 → R5 → R2 | 4 |
Une métrique de routage et une contrainte de capacité sont deux règles qu’un programme doit explicitement appliquer.
Exercice 2 · 6 points
Taquin : corriger le programme et conserver la résolubilité
Le taquin possède quinze tuiles numérotées dans une grille 4 × 4 et une case vide. Une tuile adjacente au vide peut y glisser. Le but est de retrouver la grille rangée. Une grille qui le permet est résoluble. La figure 1 présente les deux grilles suivantes, où « vide » est codé par 16 :
| Ligne | Grille rangée | Grille mélangée |
|---|---|---|
| 1 | 1, 2, 3, 4 | 14, vide, 15, 12 |
| 2 | 5, 6, 7, 8 | 5, 3, 7, 1 |
| 3 | 9, 10, 11, 12 | 2, 10, 9, 4 |
| 4 | 13, 14, 15, vide | 13, 11, 6, 8 |
À gauche les tuiles 12 et 15 peuvent bouger ; à droite 14, 15 et 3. Une grille est une liste de quatre listes contenant chacune quatre entiers ; chaque entier de 1 à 16 apparaît exactement une fois.
rangee = [[1, 2, 3, 4], [5, 6, 7, 8],
[9, 10, 11, 12], [13, 14, 15, 16]]
melangee = [[14, 16, 15, 12], [5, 3, 7, 1],
[2, 10, 9, 4], [13, 11, 6, 8]]Question 1
#Donner melangee[2][1].
Indice
Le premier indice sélectionne une ligne, le second une colonne.
Comprendre la correction
10 : l’indice 2 désigne la troisième ligne [2, 10, 9, 4] et l’indice 1 son deuxième élément. Les indices Python commencent à zéro.
Partie A : mélange aléatoire
La méthode envisagée crée une liste aplatie de 1 à 16, la mélange avec random.shuffle, puis la transforme en grille.
Question 2
#Corriger valeurs = [k for k in range(16)] pour obtenir les entiers de 1 à 16.
Indice
La longueur correcte d’une liste ne garantit pas ses bonnes bornes.
Comprendre la correction
valeurs = [k for k in range(1, 17)]La borne de départ 1 est incluse, la borne de fin 17 est exclue. La version initiale produisait 0 à 15 : elle contenait seize valeurs, mais pas les bonnes valeurs.
La documentation précise que random.shuffle(x) mélange la séquence en place, sans créer une autre instance.
from random import shuffle
valeurs = shuffle(valeurs)
print(valeurs) # NoneQuestion 3
#Corriger valeurs = shuffle(valeurs), qui remplace la liste par None.
Indice
Séparez un effet sur un objet et la valeur renvoyée par une fonction.
Comprendre la correction
shuffle(valeurs)shuffle modifie la liste en place et renvoie None. Il faut appeler la fonction sans affecter son résultat à valeurs. La liste mélangée reste accessible par la variable initiale.
def en_grille(valeurs, n):
assert ...
grille = [[0 for j in range(n)] for i in range(n)]
for i in range(n):
for j in range(n):
grille[i][j] = valeurs[j * n + i]
return grilleQuestion 4
#Compléter l’assertion de en_grille pour vérifier le nombre d’éléments.
Indice
Le nombre total de cases est lignes multipliées par colonnes.
Comprendre la correction
assert len(valeurs) == n * nUne grille n × n requiert exactement n² cases. Ce test ne vérifie pas à lui seul que les valeurs sont distinctes ou qu’elles vont de 1 à n² : la question porte seulement sur la taille.
Question 5
#L’appel en_grille([1, 2, 3, 4], 2) donne [[1, 3], [2, 4]] au lieu de [[1, 2], [3, 4]]. Corriger la ligne 6.
Indice
La case (1, 0) d’une grille 2 × 2 doit lire l’indice 2.
Comprendre la correction
grille[i][j] = valeurs[i * n + j]Avant la ligne i, il y a i lignes complètes de n éléments. On ajoute le décalage j dans cette ligne. L’ancienne expression inversait le rôle de la ligne et de la colonne, et produisait une transposition.
| Case (i,j), n=2 | Indice aplati i×n+j | Valeur de [1,2,3,4] |
|---|---|---|
| (0,0) | 0 | 1 |
| (0,1) | 1 | 2 |
| (1,0) | 2 | 3 |
| (1,1) | 3 | 4 |
La ligne suivante commence immédiatement après les n valeurs de la précédente. Pour vérifier la formule sur une taille quelconque, la dernière case (n-1,n-1) doit lire (n-1)×n+(n-1)=n²-1, dernier indice valide.
Partie B : grille résoluble
Une inversion est un couple d’indices i < j tel que valeurs[i] > valeurs[j]. Par exemple [6, 9, 7, 8] comporte (1, 2) et (1, 3), donc deux inversions. La distance du vide au coin inférieur droit est la somme des écarts de lignes et de colonnes. Dans la grille mélangée de la figure 1, elle vaut 3 + 2 = 5. On admet que la grille est résoluble exactement lorsque nombre d’inversions + distance est pair.
Question 6
#La grille [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 16, 15, 14]] est-elle résoluble ? Justifier.
Indice
Le 16 est inclus dans le comptage des inversions défini par le sujet.
Comprendre la correction
Non. Dans la liste aplatie, les seules inversions sont (16, 15), (16, 14) et (15, 14), soit 3. La case vide 16 est à la ligne d’indice 3 et colonne d’indice 1 : sa distance au coin (3, 3) vaut 2. La somme 3 + 2 = 5 est impaire. On compte bien ici les inversions impliquant 16, puisque c’est la convention de l’énoncé.
def compte_inversions(valeurs):
total = 0
for i in range(len(valeurs)):
for j in range(len(valeurs)):
if valeurs[i] > valeurs[j]:
total = total + 1
return total
assert compte_inversions([1, 2, 3, 4]) == 0Question 7
#Proposer un test avec une liste aplatie de quatre éléments possédant deux inversions.
Indice
Déplacez 1 derrière deux valeurs plus grandes.
Comprendre la correction
assert compte_inversions([2, 3, 1, 4]) == 2Les inversions sont (indice 0, indice 2), car 2 > 1, et (indice 1, indice 2), car 3 > 1. Aucun autre couple i < j ne convient. Utiliser les valeurs 1 à 4 permet en plus de rester dans le cadre d’un taquin 2 × 2.
Question 8
#La fonction ne passe pas les tests. Proposer une correction.
Indice
La définition impose deux conditions : ordre des indices et ordre des valeurs.
Comprendre la correction
def compte_inversions(valeurs):
total = 0
for i in range(len(valeurs)):
for j in range(i + 1, len(valeurs)):
if valeurs[i] > valeurs[j]:
total += 1
return totalLa seconde boucle impose désormais j > i. L’ancienne version comparait toutes les paires dans les deux sens ; pour quatre valeurs distinctes, elle comptait toujours six comparaisons vraies, même sur une liste triée. La complexité de la version corrigée reste quadratique.
Sur [2,3,1,4], i=0 compare2 aux valeurs placées après lui et trouve2>1 ; i=1 trouve3>1 ; les autres comparaisons n’ajoutent rien. Chaque paire d’indices est visitée une seule fois avec i
def distance_tuile_vide(grille, n):
num_tuile_vide = n * n
for i in range(n):
for j in range(n):
if grille[...][...] == ...:
return ...Question 9
#Compléter les lignes 5 et 6 de distance_tuile_vide.
Indice
Pour n = 4, la cible est (3, 3), pas (4, 4).
Comprendre la correction
if grille[i][j] == num_tuile_vide:
return (n - 1 - i) + (n - 1 - j)Le coin inférieur droit possède les indices (n - 1, n - 1). Tous les indices de la grille sont inférieurs ou égaux à ces deux coordonnées, donc les écarts sont déjà positifs. On cherche n², numéro conventionnel du vide, et non 0.
def est_resoluble(valeurs, n):
grille = en_grille(valeurs, n)
inv = ...(...)
dis = ...(...)
return (... + ...) ... == ...Question 10
#Compléter est_resoluble. On rappelle que 7 % 2 == 1 et 8 % 2 == 0.
PythonDécider si un taquin 4×4 peut être résoluÉcrivez votre solution et mettez-la à l’épreuve
Complétez est_resoluble(valeurs, n) pour le taquin 4×4 de cette partie : n vaut 4, valeurs est une permutation de 1 à 16 et 16 représente le vide. Les helpers sont fournis comme dans le sujet : en_grille remplit par colonnes, compte_inversions inclut le vide, et distance_tuile_vide mesure sa distance au coin inférieur droit. Appliquez le critère de parité admis sur la somme des inversions et de cette distance. Ne généralisez pas cette formule aux dimensions impaires.
def est_resoluble(valeurs,n):
# À vous de jouer
passLes cas de test proposés :
- La configuration finale : Aucune inversion, distance nulle : la somme est paire.
- Deux tuiles échangées, vide immobile : Un échange de deux tuiles modifie la parité sans changer la distance du vide.
- Un déplacement légal du vide : Une inversion et une unité de distance donnent une somme paire : tester les inversions seules serait faux.
- Le vide se déplace entre deux colonnes : Selon le remplissage par colonnes du sujet, ces deux indices sont voisins. Le déplacement produit sept inversions et une distance de 1.
- Une grille presque résolue mais impossible : Un déplacement légal suivi d’un échange de deux autres tuiles rend la parité impaire. La fonction doit seulement décider, sans jouer.
Indice
Chaque fonction attend une forme précise de données.
Comprendre la correction
def est_resoluble(valeurs, n):
grille = en_grille(valeurs, n)
inv = compte_inversions(valeurs)
dis = distance_tuile_vide(grille, n)
return (inv + dis) % 2 == 0Le modulo 2 teste la parité de la somme. Les fonctions reçoivent la bonne représentation : la liste aplatie pour les inversions, la grille pour la distance. La formule admise concerne le taquin 4 × 4 de cette partie, et convient plus généralement aux dimensions paires avec le vide inclus ; il ne faut pas la présenter comme un critère général valide pour toute dimension impaire.
Une grille peut sembler presque rangée et être pourtant irrésoluble : la propriété de parité porte sur la permutation entière, pas sur une distance visuelle intuitive à la solution. Le test ne fournit pas les mouvements à jouer ; il décide seulement de l’existence d’une solution dans le modèle étudié. Calculer effectivement un chemin est une autre tâche, que l’on peut aborder comme une recherche dans le graphe des configurations.
Partie C : mélange réaliste
Pour garantir un mélange résoluble, on part de la grille rangée et échange plusieurs fois le vide avec une tuile voisine. Les sommets du graphe sont les indices des cases, pas leurs valeurs. Une arête relie les positions entre lesquelles un glissement est possible. La liste d’adjacence donne, pour chaque indice, ses voisins. Figure 2, grille 3 × 3 :
| Indice | Voisins |
|---|---|
| 0 | 1, 3 |
| 1 | 0, 2, 4 |
| 2 | 1, 5 |
| 3 | 0, 4, 6 |
| 4 | 1, 3, 5, 7 |
| 5 | 2, 4, 8 |
| 6 | 3, 7 |
| 7 | 4, 6, 8 |
| 8 | 5, 7 |
Question 11
#Donner une valeur possible de graphe_4_4[9].
Indice
Dépliez les indices de 0 à 15 sur quatre lignes.
Comprendre la correction
[5, 8, 10, 13]L’indice 9 est à la ligne 2, colonne 1. Ses voisins haut, gauche, droite et bas portent les indices 5, 8, 10, 13. L’ordre de la liste ne compte pas. Un décalage de 1 n’est valide horizontalement que si l’on reste sur la même ligne.
random.choice renvoie un élément choisi aléatoirement dans la liste donnée. Le programme imprimé est :
from random import choice
def melange_graphe(nb_dep, n, graphe):
valeurs = [i for i in range(n*n)] # ligne imprimée, erronée
num_tuile_vide = n * n
actuelle = num_tuile_vide - 1
for k in range(...):
prochaine = choice(...)
valeurs[actuelle] = valeurs[...]
valeurs[prochaine] = ...
actuelle = prochaine
return en_grille(valeurs, n)Question 12
#Compléter les lignes 7 à 10 de melange_graphe.
Indice
La liste passée à choice doit être celle des voisins de la position actuelle du vide.
Comprendre la correction
for k in range(nb_dep):
prochaine = choice(graphe[actuelle])
valeurs[actuelle] = valeurs[prochaine]
valeurs[prochaine] = num_tuile_videLa tuile voisine remplit l’ancien vide ; son ancienne case devient vide, puis actuelle = prochaine actualise la position. Chaque mouvement est réversible : refaire tous les mouvements en sens inverse ramène à la grille rangée.
Coquille à corriger en plus dans le programme fourni : la ligne 4 produit 0 à n² - 1 alors que la convention est 1 à n². Il faut écrire valeurs = [i for i in range(1, n*n + 1)]. Compléter uniquement les quatre lignes demandées sans rectifier cette initialisation ne donne pas un taquin valide.
Le programme construit volontairement une marche dans le graphe des positions du vide. Même si les choix sont aléatoires, inverser la suite des échanges est toujours un chemin légal vers la solution, car un glissement est réversible. Cela garantit la résolubilité mais pas que la grille soit très mélangée : des mouvements peuvent s’annuler ou ramener tôt à la solution. La fonction doit conserver exactement une occurrence de chaque nombre de1 à n².
L’invariant caché derrière le taquinUn atelier pour expérimenter
Comparez trois positions, puis échangez deux tuiles numérotées. Observez comment ce simple échange modifie la parité sans déplacer le vide. Le tableau liste toutes les inversions.
Lire le résultat de l’expérience initiale
Cette grille n’est pas résoluble
Les inversions incluent la valeur 16 qui représente le vide. La formule s’applique à cette grille de dimension paire. Inversions : 16 > 15 ; 16 > 14 ; 15 > 14.
| Ligne | Colonne 1 | Colonne 2 | Colonne 3 | Colonne 4 |
|---|---|---|---|---|
| 1 | 1 | 2 | 3 | 4 |
| 2 | 5 | 6 | 7 | 8 |
| 3 | 9 | 10 | 11 | 12 |
| 4 | 13 | Vide | 15 | 14 |
Mélanger une permutation quelconque ne garantit pas une grille gagnable. Des mouvements légaux depuis la solution, eux, conservent sa résolubilité.
Exercice 3 · 8 points
Covoiturage : requêtes SQL, files et point de rendez-vous
Une entreprise multisite propose une application de covoiturage : chaque salarié peut créer un trajet ou s’y inscrire. Le but est de réduire l’usage individuel de la voiture. On peut utiliser SELECT, FROM, WHERE, AND, OR, JOIN ... ON, INSERT, UPDATE, DELETE, DISTINCT et ORDER BY. Le schéma de la figure 1 est le suivant :
| Table | Attributs | Clé primaire | Clés étrangères |
|---|---|---|---|
| utilisateur | id_utilisateur, nom, prenom | id_utilisateur | - |
| trajet | id_trajet, depart, arrivee, heure, nb_places, conducteur | id_trajet | conducteur → utilisateur.id_utilisateur |
| inscription | trajet, passager | Aucune clé soulignée sur la figure source | trajet → trajet.id_trajet ; passager → utilisateur.id_utilisateur |
Dans la figure d’origine, les attributs clés primaires sont soulignés et les clés étrangères préfixées par #. Les identifiants de trajet et d’utilisateur sont des entiers.
Question 1
#Pourquoi nom et prenom ne sont-ils pas retenus comme clé primaire de utilisateur ?
Indice
Une clé doit distinguer deux personnes homonymes.
Comprendre la correction
Deux salariés peuvent avoir le même nom et le même prénom. Leur combinaison ne garantit donc pas l’unicité d’une ligne. Un identifiant propre à chaque utilisateur reste distinct même en cas d’homonymie ou de changement de nom.
Question 2
#Pourquoi les attributs de inscription sont-ils aussi entiers ?
Indice
Suivez chaque flèche du schéma jusqu’à l’identifiant référencé.
Comprendre la correction
inscription.trajet et inscription.passager sont des clés étrangères vers des identifiants entiers. Ils doivent appartenir aux mêmes domaines de valeurs que les attributs référencés afin de représenter ces références et de permettre leur contrôle.
SELECT * FROM trajet
WHERE heure > '2026-06-19 00:00:00'
AND heure < '2026-06-20 00:00:00';Cette requête renvoie :
| id_trajet | depart | arrivee | heure | nb_places | conducteur |
|---|---|---|---|---|---|
| 1291 | Liverdun | Toul | 2026-06-19 07:30:00 | 3 | 25 |
| 1292 | Allain | Nancy | 2026-06-19 07:45:00 | 2 | 30 |
| 1293 | Messein | Nancy | 2026-06-19 08:00:00 | 2 | 10 |
| 1294 | Nancy | Messein | 2026-06-19 18:20:00 | 2 | 10 |
| 1295 | Nancy | Allain | 2026-06-19 17:45:00 | 3 | 25 |
| 1296 | Toul | Liverdun | 2026-06-19 18:00:00 | 2 | 30 |
| trajet | passager |
|---|---|
| 1291 | 4 |
| 1291 | 15 |
| 1291 | 38 |
| 1292 | 18 |
| 1295 | 4 |
| 1295 | 15 |
| 1295 | 38 |
| 1296 | 18 |
| id_utilisateur | nom | prenom |
|---|---|---|
| 4 | Mizab | Yasmine |
| 10 | Di Maria | Alexis |
| 15 | Rey | Maxime |
| 18 | Nguema | Basil |
| 25 | Daniel | Valérie |
| 30 | Sanches | Nathalie |
| 38 | Fabre | Clément |
SELECT COUNT(*)
FROM ...
WHERE ...;Question 3
#Compléter la requête pour compter les passagers du trajet 1291.
Indice
La table inscription contient une ligne par inscription.
Comprendre la correction
SELECT COUNT(*)
FROM inscription
WHERE trajet = 1291;Le résultat est 3 pour l’extrait fourni. On compte les inscriptions et non les places proposées : nb_places décrit la capacité, qui n’est pas toujours égale au nombre de passagers inscrits.
Question 4
#Lister les trajets qui arrivent à Nancy le 19 juin 2026, par heure de départ croissante.
Indice
Un intervalle de dates complet évite de confondre le 19 juin avec une chaîne approximative.
Comprendre la correction
SELECT *
FROM trajet
WHERE arrivee = 'Nancy'
AND heure >= '2026-06-19 00:00:00'
AND heure < '2026-06-20 00:00:00'
ORDER BY heure ASC;La borne basse inclusive contient tout le 19 juin, y compris un éventuel départ à minuit. La borne haute exclusive exclut le 20 juin. Avec les données fournies : 1292 à 07:45, puis 1293 à 08:00. Le champ heure décrit l’heure de départ ; aucune heure d’arrivée n’est fournie.
Question 5
#Écrire une requête qui aurait créé le trajet 1295, supposé non modifié depuis son ajout.
Indice
Recopiez toutes les informations de la ligne 1295.
Comprendre la correction
INSERT INTO trajet
(id_trajet, depart, arrivee, heure, nb_places, conducteur)
VALUES (1295, 'Nancy', 'Allain', '2026-06-19 17:45:00', 3, 25);Les valeurs suivent l’ordre des colonnes explicitement citées. Le conducteur 25 doit exister dans utilisateur. Il ne faut pas ajouter ici les inscriptions des passagers : elles sont dans une autre table.
Question 6
#Modifier l’heure de départ du trajet 1294 à 18 h 40.
Indice
Le champ heure contient à la fois date et heure.
Comprendre la correction
UPDATE trajet
SET heure = '2026-06-19 18:40:00'
WHERE id_trajet = 1294;On conserve la date du 19 juin et on cible le trajet par sa clé primaire. Sans WHERE, tous les trajets auraient été modifiés.
DELETE FROM trajet
WHERE id_trajet = 1296;ERROR 1451 (23000) at line 95 in file: 'covoit.sql':
Cannot delete or update a parent row: a foreign key constraint failsQuestion 7
#Expliquer l’erreur rencontrée lors de la suppression du trajet 1296.
Indice
Cherchez 1296 dans la table inscription.
Comprendre la correction
La ligne (1296, 18) d’inscription référence le trajet 1296. La suppression de ce trajet laisserait cette clé étrangère sans cible. Le SGBD refuse donc l’opération pour préserver l’intégrité référentielle. Il faut supprimer les inscriptions correspondantes avant le trajet, sauf si une règle de cascade a été prévue. Ce n’est ni une erreur de syntaxe de DELETE ni une confusion avec le conducteur.
Question 8
#Lister les noms et prénoms des passagers transportés au moins une fois par l’utilisatrice 25.
SQLRetrouver les passagers de la conductrice 25Écrivez votre solution et mettez-la à l’épreuve
Renvoyez sans répétition le nom et le prénom des passagers transportés au moins une fois par l’utilisatrice 25. La question ne limite pas la recherche à une seule date.
SELECT ...
FROM ...
WHERE ...;Les cas de test proposés :
- Trajets et inscriptions du sujet : Les trois tables sont reprises de l’extrait officiel. Les mêmes trois passagers sont inscrits sur deux trajets conduits par Valérie Daniel.
- Cas complémentaire : passager et conducteur sont deux rôles : Jeu complémentaire pédagogique, distinct des données officielles. La conductrice 25 est elle-même passagère d’un autre conducteur. Elle ne doit pas apparaître pour cette raison ; le trajet plus ancien reste dans le périmètre.
Indice
Trois tables relient l’identité du passager à l’identité du conducteur.
Comprendre la correction
SELECT DISTINCT u.nom, u.prenom
FROM utilisateur AS u
JOIN inscription AS i ON i.passager = u.id_utilisateur
JOIN trajet AS t ON t.id_trajet = i.trajet
WHERE t.conducteur = 25;On part des passagers, rejoint leurs inscriptions puis les trajets concernés. DISTINCT élimine les doublons de projection, car un passager peut voyager plusieurs fois avec la conductrice. Dans l’extrait, on retrouve Yasmine Mizab, Maxime Rey et Clément Fabre. La requête ne limite pas les trajets à une journée, car la question dit « au moins une fois » sans restriction de date.
La jointure sur inscription.passager choisit bien les passagers : relier utilisateur directement à trajet.conducteur retournerait la conductrice au lieu des personnes transportées. La deuxième jointure associe chaque inscription à son trajet. Le filtre conducteur=25 garde alors les voyages pertinents, même si le passager y figure plusieurs fois.
Partie B : choisir le rendez-vous
Alice, Maxime, Valérie et Clément habitent aux sommets A, M, V et C. Ils envisagent les points P1, P2, P3. Chaque arête représente un trajet de distance et de durée approximativement comparables ; on mesure donc les distances en nombres d’arêtes.
Lire les connexions du schéma
- C relié à P1
- C relié à P2
- P1 relié à A
- A relié à P2
- A relié à P3
- P2 relié à M
- P3 relié à M
- M relié à V
Question 9
#Écrire le dictionnaire associant chaque sommet de la figure 2 à ses voisins.
Indice
Vérifiez chaque liaison dans les deux sens.
Comprendre la correction
graphe = {
"C": [
"P1",
"P2"
],
"P1": [
"C",
"A"
],
"A": [
"P1",
"P2",
"P3"
],
"P2": [
"C",
"A",
"M"
],
"P3": [
"A",
"M"
],
"M": [
"P2",
"P3",
"V"
],
"V": [
"M"
]
}Le graphe n’est pas orienté : chaque arête doit être présente dans les deux listes correspondantes. Les positions sur le dessin ne créent pas de liaison implicite. Par exemple V ne possède que M pour voisin ; P2 et P3 ne sont pas directement reliés.
def dico_distance(graphe, depart):
"""Renvoie les distances de depart aux sommets atteignables."""
file = File()
file.inserer(depart)
dico = {depart: 0}
while not file.est_vide():
sommet = file.extraire()
for voisin in graphe[sommet]:
if voisin not in dico:
dico[voisin] = dico[sommet] + 1
file.inserer(voisin)
return dico| Méthode de File | Contrat |
|---|---|
__init__() | Crée une file vide |
consulter() | Renvoie le premier élément sans le retirer ; IndexError si vide |
est_vide() | True si vide, False sinon |
extraire() | Renvoie et retire le premier élément ; IndexError si vide |
| inserer(element) | Ajoute l’élément en file |
Question 10
#Rappeler le principe d’une file.
Indice
Pensez à l’ordre d’une queue d’attente.
Comprendre la correction
Une file suit la règle premier entré, premier sorti, ou FIFO. Une insertion se fait à une extrémité et une extraction à l’autre. Ainsi, un sommet découvert avant un autre est exploré avant lui. Une pile suivrait au contraire la règle dernier entré, premier sorti.
Question 11
#Donner un ordre possible d’insertion des sommets dans la file en partant de P1.
Indice
Écrivez la file après chaque extraction et insertion ; n’insérez pas un sommet déjà dans dico.
Comprendre la correction
Avec l’ordre des voisins du dictionnaire proposé : P1, C, A, P2, P3, M, V. P1 découvre C et A ; C découvre P2 ; A découvre P3 (P2 est déjà marqué) ; P2 découvre M ; M découvre V. Chaque sommet est inscrit dans dico dès son insertion, ce qui évite de l’insérer plusieurs fois. D’autres ordres sont possibles si l’ordre des voisins change.
Question 12
#Quel type de parcours est utilisé par dico_distance ?
Indice
Le choix file ou pile détermine l’ordre d’exploration.
Comprendre la correction
Un parcours en largeur. La file fait explorer les sommets par distance croissante ; chaque voisin inédit reçoit la distance de son prédécesseur plus un. Sur ce graphe non pondéré, c’est sa distance minimale au départ.
On définit l’excentricité d’un sommet comme sa plus grande distance à un autre sommet du graphe.
def excentricite(graphe, sommet):
"""Renvoie l’excentricité de sommet dans graphe (int)."""
dico = dico_distance(graphe, sommet)
...
...
...
...
...Question 13
#Compléter excentricite sans utiliser max.
Indice
Conservez la meilleure valeur vue jusqu’ici et mettez-la à jour seulement lorsqu’elle augmente.
Comprendre la correction
def excentricite(graphe, sommet):
dico = dico_distance(graphe, sommet)
plus_grande = 0
for s in dico:
if dico[s] > plus_grande:
plus_grande = dico[s]
return plus_grandeL’excentricité est la plus grande distance du sommet aux autres sommets. Le dictionnaire contient des distances non négatives ; initialiser à zéro convient, y compris pour un graphe réduit à un sommet. Le graphe du sujet est connexe. Sur un graphe non connexe, ce programme donnerait seulement le maximum dans la composante atteignable, ce qu’il faudrait distinguer d’une excentricité globale infinie ou non définie selon la convention.
L’invariant de la boucle est : plus_grande est la plus grande distance parmi les entrées déjà traitées. Initialiser à0 est correct puisque les distances ne sont jamais négatives et que le sommet de départ se trouve dans dico à distance0. En fin de parcours, toutes les distances atteignables ont été comparées. Il ne faut pas comparer les noms des sommets s entre eux : ce sont les valeurs dico[s] qui mesurent l’éloignement.
Question 14
#Choisir le meilleur point de rendez-vous, avec un indicateur justifié.
Indice
Comparez la distance du domicile le plus éloigné pour chaque point candidat.
Comprendre la correction
| Point | Distance à A | à M | à V | à C | Maximum | Somme |
|---|---|---|---|---|---|---|
| P1 | 1 | 3 | 4 | 1 | 4 | 9 |
| P2 | 1 | 1 | 2 | 1 | 2 | 5 |
| P3 | 1 | 1 | 2 | 3 | 3 | 7 |
P2 minimise le plus grand trajet : personne ne parcourt plus de deux arêtes. Ses distances à P1 et P3 valent aussi 2, donc son excentricité globale est 2, contre 4 pour P1 et 3 pour P3. P2 minimise également la somme des distances des quatre domiciles (5), mais ce second indicateur est distinct : il est ici cohérent avec la minimisation du trajet le plus défavorisé.
Choisir un rendez-vous équitableUn atelier pour expérimenter
Choisissez P1, P2 ou P3 comme départ. Le parcours calcule toutes les distances ; comparez le trajet maximal et la distance totale des quatre covoitureurs.
Lire le résultat de l’expérience initiale
Rendez-vous P1
La file explore les distances par couches. Pour l’équité, on minimise le plus long trajet des quatre domiciles ; pour l’effort collectif, on regarde la somme.
| Sommet | Distance | Nature |
|---|---|---|
| P1 | 0 | Rendez-vous possible |
| C | 1 | Domicile |
| A | 1 | Domicile |
| P2 | 2 | Rendez-vous possible |
| P3 | 2 | Rendez-vous possible |
| M | 3 | Domicile |
| V | 4 | Domicile |
Un « meilleur » point dépend d’un critère annoncé. Ici P2 minimise à la fois le pire trajet et la distance collective.
Revoir les notions de cet exercice
Du sujet à la méthode
Votre prochaine séance de révision
- Faites apparaître la correspondance entre les cases et leurs indices : beaucoup d’erreurs du taquin viennent d’un mélange indice/valeur.
- Pour une requête SQL, écrivez d’abord les jointures nécessaires puis ajoutez les filtres.
- Lorsque le sujet demande un indicateur, donnez sa valeur pour chaque candidat et expliquez pourquoi on le minimise.
Retrouver ces notions dans d’autres sujets
Toutes les annales de NSI · Le guide pour préparer le bac NSI 2027
Énoncé : sujet 26-NSIJ2ME1 (PDF). Corrigé et explications pédagogiques proposés par Sofien.
