Exercice 3 Amérique du Nord – Bac NSI 2025 – Jour 2
mots clés: BDD, programmation, récursivité, graphes
🔎 Voir les exercices similaires ↓
Amérique du Nord – Bac NSI 2025 – Jour 2 Énoncé de l'exercice 3
Cet exercice porte sur les bases de données, la programmation en Python, la récursivité et les algorithmes de parcours de graphes.
Partie A
Dans cette partie, on pourra utiliser les clauses du langage SQL pour :
construire des requêtes d’interrogation à l’aide de SELECT, FROM, WHERE (avec les opérateurs logiques AND, OR), JOIN … ON ;
construire des requêtes d’insertion et de mise à jour à l’aide de UPDATE, INSERT, DELETE ;
affiner les recherches à l’aide de DISTINCT, ORDER BY.
La compagnie aérienne AirInfo souhaite utiliser un système de gestion de bases de données relationnelles afin de l’aider à gérer les informations dont elle dispose sur les aéroports desservis, les vols proposés, les passagers et les réservations effectuées par ces passagers.
Elle crée donc la base de données compagnie_aerienne, constituée de quatre relations. Le schéma relationnel de cette base de données est le suivant :
- aeroport (id_aeroport : TEXT, ville : TEXT, pays : TEXT)
- vol (id_vol : TEXT, aeroport_dep : TEXT, aeroport_arr : TEXT, distance : INT)
- passager (id_passager : INT, nom : TEXT, prenom : TEXT, ville : TEXT, d_totale : INT)
reservation (id_vol : TEXT, id_passager : INT)
Une clé primaire de la relation vol est l’attribut id_vol. Les autres clés primaires et étrangères ne sont pas précisées. Les quatre tables ci-après constituent, en l’état, la base de données compagnie_aerienne complète.
Les valeurs des champs distance et d_totale intervenant respectivement dans les tables vol et passager sont exprimées en milliers de kilomètres.
| aeroport | ||
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| vol | |||
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| passager | ||||
|---|---|---|---|---|
|
nom |
|
ville | d_totale |
| 1 | Dupont | Alice | Paris | 6 |
| 2 | Smith | John |
|
6 |
| 3 | Brown | Sarah | Berlin | 9 |
| 4 |
|
Taro | Tokyo | 17 |
| 5 | Williams | Emma | Sydney | 10 |
| reservation | |
|---|---|
|
id_passager |
| AI0006 | 1 |
| AI0006 | 2 |
| AI0256 | 4 |
| AI0276 | 5 |
| AI1681 | 3 |
Expliquer pourquoi l’attribut id_vol ne peut pas être une clé primaire de la table reservation.
Proposer une clé primaire pour la table reservation.
Expliquer le rôle d’une clé étrangère dans une relation.
Écrire le résultat renvoyé par la requête SQL suivante :
SELECT id_vol FROM vol WHERE aeroport_arr = 'CDG';
Écrire une requête SQL qui donne les noms des villes qui sont destination d’un vol au départ de l’aéroport CDG.
La compagnie AirInfo envisage de récompenser la fidélité de ses usagers en tenant compte de la distance totale qu’ils parcourent sur leurs lignes. Ainsi, à chaque nouvelle réservation, la table passager doit être mise à jour : si l’usager avait déjà parcouru une distance totale 𝑑totale, puis réserve un vol d’une distance 𝑑vol, l’attribut d_totale est modifié en prenant pour nouvelle valeur 𝑑totale +𝑑vol.
La passagère d’identifiant 5 a déjà parcouru 10 milliers de kilomètres. Elle réserve un vol de Washington (IAD) à Paris (CDG), d’une distance de 6 milliers de kilomètres.
Écrire la requête permettant de mettre à jour la table passager.
La compagnie aérienne offre maintenant la possibilité de relier Paris CDG à Montréal YUL (Canada) par un vol de 6 milliers de kilomètres. Afin de prendre en compte ce nouveau trajet dans la base de données, on souhaite l’ajouter dans la table vol dont la clé primaire est id_vol. On propose, de manière incorrecte, la requête d’insertion ci-après :
INSERT INTO vol
VALUES ('AI0256', 'CDG', 'YUL', 6);
Proposer, en justifiant, une correction relative à l’erreur commise.
Partie B
Dans cette partie, on considère les villes suivantes : Washington (W) ; Paris (P) ; Berlin (B) ; Tokyo (T) ; Sydney (S).
Les distances des vols entre ces villes, exprimées en milliers de kilomètres, sont les suivantes :
Washington - Paris : 6 ;
Washington - Berlin : 7 ;
Paris - Berlin : 1 ;
Paris - Tokyo : 10 ;
Paris - Sydney : 17 ;
Berlin - Tokyo : 9 ;
Tokyo - Sydney : 8.
La compagnie AirInfo propose certains de ces vols. Son réseau aérien est représenté par le graphe pondéré non orienté de la Figure 1 dans lequel :
chaque ville est représentée par un sommet ;
chaque vol direct entre deux villes est représenté par une arête.
Le nombre indiqué sur chaque arête est appelé poids : il représente la distance entre deux villes. Cette distance est la même dans un sens ou dans l’autre.

Figure 1. Graphe non orienté pondéré correspondant au réseau aérien de la compagnie AirInfo
On choisit de représenter ce graphe en Python à l’aide d’un dictionnaire dans lequel chaque clé est un sommet du graphe et la valeur associée à cette clé est elle-même un dictionnaire, dont les clés sont les villes voisines et les valeurs sont les distances correspondantes.
Le dictionnaire associé au graphe, représenté par la Figure 1, est donné ci-après.
graphe_airinfo = {
'W': {'P': 6},
'P': {'W': 6, 'T': 10, 'S': 17},
'B': {'T': 9},
'T': {'B': 9, 'P': 10, 'S': 8},
'S': {'P': 17, 'T': 8}
}
Déterminer la valeur de l’expression graphe_airinfo['T']['P'].
Écrire le code d’une fonction Python vol_direct permettant de déterminer s’il existe une liaison directe entre deux villes. Cette fonction prend en paramètres un dictionnaire graphe représentant le graphe, et deux clés du dictionnaire ville1 et ville2 représentant deux villes, et renvoie True si une telle liaison entre les villes ville1 et ville2 existe, c’est-à-dire si les deux sommets ville1 et ville2 sont reliés dans le graphe graphe par une arête, False sinon.
Exemples :
>>> vol_direct(graphe_airinfo, 'T', 'B')
True
>>> vol_direct(graphe_airinfo, 'W', 'B')
False
Afin de limiter leurs empreintes carbone, les voyageurs demandent fréquemment aux compagnies aériennes de déterminer, à partir d’une ville donnée, la liste des villes qu’il est possible d’atteindre par un vol direct tout en ne dépassant pas une certaine distance.
Écrire le code d’une fonction Python liste_villes_proches qui permet de répondre à la demande des voyageurs. Cette fonction prend en paramètres un dictionnaire graphe représentant le graphe, une clé du dictionnaire ville et un entier d_max représentant une distance et renvoie la liste des villes reliées à ville par une arête dans graphe dont le poids est au plus égal à d_max.
Exemples :
>>> liste_villes_proches(graphe_airinfo, 'T', 7) [] >>> liste_villes_proches(graphe_airinfo, 'T', 9) ['B', 'S']
La compagnie aérienne Droidevant, concurrente de la compagnie AirInfo, assure des liaisons différentes. Son réseau aérien peut également être représenté par un graphe dont le dictionnaire correspondant en Python est donné ci-après.
graphe_droidevant = {
'W': {'P': 6, 'B': 7},
'P': {'W': 6, 'B': 1},
'B': {'W': 7, 'P': 1},
'T': {'S': 8},
'S': {'T': 8}
}
Dessiner, en indiquant le poids sur chaque arête, le graphe représentant le réseau aérien de la compagnie Droidevant.
On dit qu’un graphe est connexe s’il existe un chemin entre chaque paire de sommets, autrement dit, si pour tout sommet s1 et pour tout sommet s2, il existe un chemin entre s1 et s2 dans le graphe.
Indiquer, parmi les deux propositions suivantes, celle qui est correcte :
− Proposition A : le graphe de la compagnie AirInfo est connexe ;
− Proposition B : le graphe de la compagnie Droidevant est connexe.
On peut adapter un algorithme de parcours de graphe pour déterminer si un graphe est connexe.
On considère la fonction parcours qui permet d’explorer les villes d’un graphe accessibles à partir d’une ville donnée et qui prend en paramètres :
graphe : un dictionnaire représentant le graphe ;
visitees : une liste des villes déjà visitées ;
ville : la ville actuelle à partir de laquelle on effectue l’exploration.
def parcours(graphe, visitees, ville):
"""Parcours d'un graphe à partir d'une ville non
visitée, en ayant déjà visité un certain nombre de
villes.
"""
# Marque la ville comme visitée
visitees.append(ville)
# Parcourt les voisines de la ville
for voisine in graphe[ville]:
if voisine not in visitees:
# Explore depuis les voisines non visitées
parcours(graphe, visitees, voisine)
Expliquer en quoi la fonction parcours est une fonction récursive.
Déterminer le contenu des variables visitees1 et visitees2 après l’exécution des lignes de code données ci-après.
visitees1 = []
parcours(graphe_airinfo, visitees1, 'W')
visitees2 = []
parcours(graphe_droidevant, visitees2, 'W')
Indiquer, parmi les propositions suivantes, laquelle correspond au type de parcours effectué par la fonction parcours :
-- Proposition A : un parcours en largeur ;
-- Proposition B : un parcours en grandeur
-- Proposition C : un parcours en profondeur.
On cherche à écrire une fonction est_connexe qui prend en paramètre un graphe, représenté à l’aide d’un dictionnaire de dictionnaires de voisins, et qui renvoie True si le graphe est connexe, False sinon.
On admet disposer d’une fonction ville_arbitraire qui renvoie un sommet arbitraire d’un graphe.
Par exemple, ville_arbitraire(graphe_airinfo) pourrait renvoyer 'T' ou n’importe quel autre sommet.
On considère le code de la fonction Python incomplet suivant :
def est_connexe(graphe):
"""Vérifie si un graphe est connexe."""
depart = ville_arbitraire(graphe)
visitees = ... # ligne 4
parcours(graphe, visitees, depart)
return ... # ligne 6
16. Recopier et compléter les lignes 4 et 6 du code de la fonction est_connexe. On pourra, si nécessaire, ajouter de nouvelles lignes.
On considère maintenant le code de la fonction, donné ci-après, mystere, qui prend en paramètres :
graphe, un dictionnaire représentant un graphe ;
ville, une clé du dictionnaire graphe représentant une ville de départ ;
chemin, une liste de clés représentant les villes ;
cout, un entier représentant une distance ;
arrivee, une clé du dictionnaire graphe représentant une ville d’arrivée.
def mystere(graphe, ville, chemin, cout, arrivee):
# Ajoute la ville actuelle au chemin
chemin = chemin + [ville]
if ville == arrivee:
# Affiche le chemin et son coût total
print(chemin, cout)
# Parcourt les villes voisines et leurs poids
for voisine, poids in graphe[ville].items():
# Vérifie que la ville n'est pas déjà visitée
if voisine not in chemin:
mystere(graphe, voisine, chemin, cout + poids, arrivee)
Déterminer les affichages produits lors de l’exécution de l’appel suivant :
mystere(graphe_airinfo, 'W', [], 0, 'B')
Expliquer, de manière générale, ce que réalise l’appel mystere(graphe, ville, [], 0, arrivee) pour un graphe graphe et deux villes ville et arrivee.
Amérique du Nord – Bac NSI 2025 – Jour 2 Correction de l'exercice 3
Partie A – Base de données
1. Clé primaire de la table reservation
L’attribut id_vol ne peut pas être une clé primaire de la table reservation car un même vol peut être réservé par plusieurs passagers. Il apparaît donc plusieurs fois dans la table.
2. Clé possible
Une clé primaire possible pour la table reservation est le couple (id_vol, id_passager), qui identifie de manière unique une réservation.
3. Rôle d’une clé étrangère
Une clé étrangère permet d’assurer l’intégrité référentielle : elle garantit que la valeur stockée correspond à une clé primaire existante dans une autre table.
4. Résultat de la requête SQL
La requête renvoie les identifiants des vols dont l’aéroport d’arrivée est CDG :
AI0015
AI0258
AI0292
5. Villes destination depuis CDG
SELECT DISTINCT aeroport.ville
FROM vol
JOIN aeroport ON vol.aeroport_arr = aeroport.id_aeroport
WHERE vol.aeroport_dep = 'CDG';
6. Mise à jour de la distance totale
UPDATE passager
SET d_totale = d_totale + 6
WHERE id_passager = 5;
7. Correction de l’erreur d’insertion
L’identifiant AI0256 existe déjà (vol CDG → SYD) : id_vol étant la clé primaire de vol, l’insertion est refusée. Il faut choisir un identifiant de vol encore inutilisé, par exemple :
INSERT INTO vol
VALUES ('AI1900', 'CDG', 'YUL', 6);
Partie B – Graphes pondérés
8. Valeur de graphe_airinfo['T']['P']
La valeur est 10, correspondant à la distance entre Tokyo et Paris.
9. Fonction vol_direct
def vol_direct(graphe, ville1, ville2):
return ville2 in graphe[ville1]
10. Fonction liste_villes_proches
def liste_villes_proches(graphe, ville, d_max):
proches = []
for v in graphe[ville]:
if graphe[ville][v] <= d_max:
proches.append(v)
return proches
11. Graphe de la compagnie Droidevant

Le graphe comporte deux parties qui ne sont pas reliées entre elles : W–P–B et T–S.
12. Connexité des graphes
La bonne réponse est la proposition A : le graphe d’AirInfo est connexe. Celui de Droidevant ne l’est pas : il n’existe aucun chemin de W à T.
13. Fonction parcours
La fonction est récursive car elle s’appelle elle-même pour explorer les voisins non encore visités d’un sommet.
14. Contenu des variables visitees1 et visitees2
visitees1 = ['W', 'P', 'T', 'B', 'S']
visitees2 = ['W', 'P', 'B']
15. Type de parcours
Il s’agit d’un parcours en profondeur (proposition C) : on explore entièrement une voisine avant de passer à la suivante.
16. Fonction est_connexe
def est_connexe(graphe):
depart = ville_arbitraire(graphe)
visitees = [] # ligne 4
parcours(graphe, visitees, depart)
return len(visitees) == len(graphe) # ligne 6
17. Affichages produits
Affichages produits par mystere(graphe_airinfo, 'W', [], 0, 'B') :
['W', 'P', 'T', 'B'] 25
['W', 'P', 'S', 'T', 'B'] 40
18. Fonction mystere
L’appel affiche tous les chemins de ville à arrivee qui ne passent pas deux fois par la même ville, chacun suivi de sa longueur totale (somme des poids des arêtes).
Une erreur, un oubli ? Écrivez-moi : frederic.peuriere@lfcl.pt
🔎 Exercices sur des thèmes similaires
-
Amérique du Nord 2026 – jour 1 – exercice 3
récursivité, programmation dynamique, BDD, SQL — Difficulté : 🔥🔥🔥🔥🔥 -
Nouvelle Caldédonie 2023 – jour 2 – exercice 2
programmation Python, récursivité — Difficulté : 🔥🔥🔥🔥🔥 -
Métropole 2025 – jour 2 – exercice 2
BDD, SQL, programmation — Difficulté : 🔥🔥🔥🔥🔥 -
Centres étrangers 2024 – jour 1 – exercice 3
programmation, POO, BDD, SQL — Difficulté : 🔥🔥🔥🔥🔥 -
Asie 2024 – jour 2 – exercice 3
BDD, SQL, programmation — Difficulté : 🔥🔥🔥🔥🔥 -
Centres étrangers 2024 – jour 2 – exercice 1
programmation, POO, récursivité — Difficulté : 🔥🔥🔥🔥🔥