Maths & NSI

Baccalauréat — Métropole J1 — 2025 — NSI

Bac NSI 2025 — Métropole — Sujet 1

Sujet

Sujet officiel du baccalauréat général, épreuve d'enseignement de spécialité numérique et sciences informatiques, session 2025, Métropole, jour 1 (épreuve du mardi 17 juin 2025). Durée 3 heures 30, calculatrice non autorisée. Le sujet comporte 3 exercices indépendants, à traiter tous les trois. Barème : exercice 1 (6 points, 10 questions), exercice 2 (6 points, 10 questions), exercice 3 (8 points, 17 questions) — soit 37 questions au total.

Exercice 1 (6 points) — Bases de données relationnelles et requêtes SQL

Dans cet exercice, 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 ; des requêtes d'insertion et de mise à jour à l'aide de UPDATE, INSERT, DELETE ; et affiner les recherches à l'aide de DISTINCT, ORDER BY.

Dans un schéma relationnel, la clé primaire d'une relation est définie par son attribut souligné, et les attributs précédés de # sont des clés étrangères.

Le guitariste Slash possède une incroyable collection de guitares. Maud est une grande fan de Slash. Elle décide de faire un inventaire de la collection sous la forme d'une base de données relationnelle.

Partie A

Maud utilise la relation suivante :

inventaire (id, marque, modele, annee, num_ser, prix)

(id est la clé primaire). num_ser représente le numéro de série d'une guitare : il est unique pour chaque guitare d'une même marque. Le prix est en euro.

Extrait de la table inventaire :

idmarquemodeleanneenum_serprix
1GibsonLes Paul Goldtop1956@70562100000
2GibsonLes Paul Goldtop19888173834920000
3GibsonLes Paul Standard1959@90663250000
4GibsonLes Paul Standard19878175753225000
5FenderTelecaster1952000230150000
6FenderTelecaster19658134567310000
7FenderStratocaster1956001359200000
8FenderStratocaster19658175753215000

1. Expliquer pourquoi l'attribut num_ser ne peut pas être une clé primaire de la relation inventaire.

2. Donner, sous forme de tableau, le résultat de la requête suivante appliquée à l'extrait de table précédent.

SELECT marque, modele
FROM inventaire
WHERE annee = 1956

3. Écrire une requête SQL permettant d'obtenir toutes les années du modèle Les Paul Standard dans la collection.

4. Écrire une requête SQL permettant d'obtenir tous les modèles de guitares de la marque Gibson par ordre croissant de l'année dans la collection.

5. Maud a fait une erreur de saisie pour la guitare d'identifiant id=1. L'année est en réalité 1957. Écrire une requête SQL permettant de corriger cette erreur de saisie.

Partie B

Maud change de représentation pour l'inventaire de la collection. Elle utilise désormais trois relations :

marque (id, nom) modele (id, nom, #id_marque) guitare (id, #id_modele, annee, num_ser, prix)

Dans modele, #id_marque référence la clé primaire id de marque. Dans guitare, #id_modele référence la clé primaire id de modele.

Extraits des trois tables :

marque

idnom
1Gibson
2Fender

modele

idnomid_marque
1Les Paul Goldtop1
2Les Paul Standard1
3Telecaster2
4Stratocaster2

guitare

idid_modeleanneenum_serprix
111956@70562100000
2119888173834920000
321959@90663250000
4219878175753225000
531952000230150000
6319658134567310000
741956001359200000
8419658175753215000

6. Expliquer brièvement, en justifiant, dans quel ordre les trois tables doivent être créées.

7. Écrire une requête SQL permettant d'obtenir le numéro de série et l'année de toutes les guitares Les Paul Standard de la collection.

Slash a fait cadeau d'une de ses guitares à un ami : Maud doit la retirer de sa base de données.

8. Écrire une requête SQL permettant de retirer de la collection la guitare d'identifiant id=3.

Slash a aussi acheté une guitare d'une marque qu'il n'avait pas encore dans sa collection. Maud décide de la rajouter.

9. Écrire l'ensemble des requêtes SQL permettant d'ajouter la guitare suivante : marque BC Rich, modèle Mockingbird, année 1992, numéro de série 92R, prix 5000. On suppose que l'on peut attribuer la valeur 3 pour l'id de la marque BC Rich, la valeur 5 pour l'id du modèle Mockingbird, et la valeur 9 pour l'id de cette guitare.

Maud souhaite connaître la valeur totale des modèles Stratocaster de la collection, à l'aide de la fonction SUM (SELECT SUM(nom_colonne) FROM tab calcule la somme des valeurs de la colonne nom_colonne de la table tab).

10. Écrire une requête SQL permettant de calculer la valeur totale des modèles Stratocaster de la collection de Slash.

Exercice 2 (6 points) — Algorithmique, structures de données et gestion de processus

On cherche à créer une application de type liste de tâches à faire pour aider Alice à planifier sa journée. Une tâche saisie par Alice est représentée par un objet Tache, muni de quatre attributs : numero (saisi par Alice), nom (saisi par Alice), duree (entier en minutes, saisi par Alice) et duree_restante (entier en minutes, initialisé avec la durée totale). Avancer de n minutes (n entier positif) dans une tâche diminue de n sa durée restante ; une tâche est terminée si sa durée restante est négative ou nulle.

Lors de la planification (aucune tâche commencée), Alice liste :

NuméroNomDurée
1Répondre aux e-mails45
2Ranger ma chambre60
3Réviser la NSI90
4S'entraîner aux échecs30
5Apprendre le vocabulaire de chinois30
6Lire Fondation60
7Écrire ma lettre au Père Noël20

(la colonne « Durée restante » est identique à « Durée », aucune tâche n'ayant commencé).

On dispose de la classe Tache ci-dessous :

class Tache:
    def __init__(self, numero, nom, duree):
        self.numero = numero
        self.nom = nom
        self.duree_initiale = duree
        self.duree_restante = duree
 
    def __repr__(self):
        return '<t'+str(self.numero)+'>'

1. Donner le code Python qui permet d'instancier deux variables tache1 et tache2 représentant : tâche numéro 1, « Répondre aux e-mails », durée estimée 45 minutes ; tâche numéro 2, « Ranger ma chambre », durée estimée 60 minutes. On suppose dans la suite que tache1, ..., tache7 représentent ainsi les sept tâches d'Alice. La méthode __repr__ permet d'avoir print(tache1) qui affiche <t1>.

2. Recopier et compléter le code de la méthode avancer de la classe Tache, qui avance la tâche self de n minutes.

def avancer(self, n):
    ...

3. Recopier et compléter le code de la méthode est_terminee, qui renvoie True si la tâche est terminée, False sinon.

def est_terminee(self):
    ...

On associe à chaque tâche une priorité (entier ≥ 1 ; plus le nombre est grand, plus la tâche est prioritaire). Les tâches sont stockées dans une file dont les éléments sont des tuples (tache, priorite), respectant deux conditions : Condition 1, les éléments sont rangés par ordre décroissant de priorité (l'élément le plus prioritaire en tête de file) ; Condition 2, parmi des éléments de même priorité, ils sont rangés dans l'ordre où ils ont été insérés (le premier inséré reste devant).

Exemple, la file de tâches f :

[début] (<t3>, 4) (<t1>, 3) (<t2>, 3) (<t4>, 1) (<t5>, 1) [fin]

signifie : la tâche de priorité maximale est <t3> ; viennent ensuite <t1> puis <t2> (toutes deux de priorité 3, <t1> insérée avant <t2>) ; aucune tâche de priorité 2 ; les moins prioritaires sont <t4> puis <t5> (priorité 1, <t4> insérée avant <t5>).

4. Représenter l'état de la file f ci-dessus lorsqu'on lui ajoute successivement la tâche numéro 6 avec la priorité 2, puis la tâche numéro 7 avec la priorité 4, en respectant les conditions 1 et 2.

On suppose déjà définies pour la classe File : File() (crée une file vide) ; enfiler(self, e) (ajoute e en fin de file) ; defiler(self) (renvoie et supprime le premier élément) ; examiner(self) (renvoie sans supprimer le premier élément) ; est_vide(self) (renvoie True si la file est vide).

5. En repartant de la file f [début] (<t3>, 4) (<t1>, 3) (<t2>, 3) (<t4>, 1) (<t5>, 1) [fin], donner la valeur de f.defiler()[0], et représenter le contenu de f après l'exécution.

6. En repartant de la même file f initiale, donner la valeur de f.examiner()[1], et représenter le contenu de f après l'exécution.

On souhaite écrire ajouter_file_prio(f, t, p), qui ajoute le tuple (t, p) à la bonne position dans la file f : on remplit une file auxiliaire f_aux en défilant les éléments en début de f tant que la priorité du premier élément est supérieure ou égale à p, puis on enfile (t, p) dans f_aux, puis on défile tous les éléments restants de f dans f_aux, et enfin on enfile dans f tous les éléments de f_aux.

7. Recopier et compléter le code de ajouter_file_prio.

def ajouter_file_prio(f, t, p):
    f_aux = File()
    while ...:
        ...
        ...enfiler(...)
    while not ...:
        ...
    while not ...:
        ...

8. Donner le coût d'exécution temporel dans le pire des cas de ajouter_file_prio, en fonction du nombre m d'éléments de la file f.

L'application propose ensuite un planning « Pomodoro » : la tâche en tête de file est défilée, avancée de 25 minutes ; si elle n'est pas terminée, elle est remise dans la file avec la fonction ajouter_file_prio et sa priorité initiale ; si elle se termine, Alice se repose le reste des 25 minutes ; on répète tant que la file n'est pas vide.

On reprend les sept tâches d'Alice, ajoutées à la file de priorité dans cet ordre :

NuméroNomDuréePriorité
3Réviser la NSI904
7Écrire ma lettre au Père Noël204
1Répondre aux e-mails453
2Ranger ma chambre603
6Lire Fondation602
4S'entraîner aux échecs301
5Apprendre le vocabulaire de chinois301

9. Indiquer, pour chaque bloc de 25 minutes, la tâche qui avance, jusqu'à la fin de toutes les tâches.

10. Écrire le code d'une fonction planning qui prend en paramètre une file de priorité f (éléments (tache, prio)) et renvoie la liste des tâches, dans l'ordre où elles sont effectuées par tranche de 25 minutes (méthode Pomodoro). Par exemple :

file = File()
for t, p in [(tache1, 3), (tache2, 3), (tache3, 4)]:
    ajouter_file_prio(file, t, p)
print(planning(file))

doit afficher [<t3>, <t3>, <t3>, <t3>, <t1>, <t2>, <t1>, <t2>, <t2>] (avec tache3 de durée 90, tache1 de durée 45, tache2 de durée 60).

Exercice 3 (8 points) — Architecture matérielle (réseau), arbres binaires de recherche et programmation Python

L'entreprise CaféNet possède plusieurs cafés répartis dans différentes villes. Le réseau de la chaîne de cafés est représenté par un schéma (figure 1, décrit ci-dessous car il ne peut pas être reproduit tel quel). Le schéma comporte 4 routeurs (numérotés 1 à 4), le réseau du siège social, le réseau du café 1 et le réseau du café 2. Dans les réseaux du café 1 et du café 2, des bornes de commande sont connectées à des switchs (boîtiers de connexion qui n'ont pas eux-mêmes d'adresse IP). Les 4 routeurs possèdent chacun au moins 3 interfaces réseau, chaque interface ayant sa propre adresse IPv4 sur le réseau auquel elle est reliée. Les masques de sous-réseau sont tous 255.255.255.0 : les trois premiers octets d'une adresse IP codent l'adresse réseau, le dernier octet code l'adresse de la machine à l'intérieur du sous-réseau.

Description du schéma (figure 1, topologie et adressage ; figure 2, type de chaque liaison) :

  • Réseau du siège social, sous-réseau 192.168.10.0/24, relié via un switch à une interface du routeur 4 (192.168.10.1). Machines : un ordinateur (192.168.10.2), une imprimante (192.168.10.3), un serveur de sauvegarde (192.168.10.10).
  • Réseau du café 1, sous-réseau 192.168.20.0/24, relié via un switch à une interface du routeur 2 (192.168.20.1). Deux bornes de commande : 192.168.20.10 et 192.168.20.11.
  • Réseau du café 2, sous-réseau 192.168.30.0/24, relié via un switch à une interface du routeur 3 (192.168.30.1). Deux bornes de commande : 192.168.30.10 et 192.168.30.11.
  • Liaison routeur 4 — routeur 3 (fibre optique) : sous-réseau 172.16.2.0/24 (interface 172.16.2.1 sur le routeur 4, 172.16.2.2 sur le routeur 3).
  • Liaison routeur 4 — routeur 1 (Ethernet) : sous-réseau 172.16.1.0/24 (interface 172.16.1.1 sur le routeur 4, 172.16.1.2 sur le routeur 1).
  • Liaison routeur 1 — routeur 3 (Ethernet) : sous-réseau 172.16.0.0/24 (interface 172.16.0.2 sur le routeur 1, 172.16.0.1 sur le routeur 3).
  • Liaison routeur 1 — routeur 2 (Fast Ethernet) : sous-réseau 172.16.3.0/24 (interface 172.16.3.2 sur le routeur 1, 172.16.3.1 sur le routeur 2).
  • Liaison routeur 3 — routeur 2 (Fast Ethernet) : sous-réseau 172.16.4.0/24 (interface 172.16.4.2 sur le routeur 3, 172.16.4.1 sur le routeur 2).
  • Le routeur 1 possède en outre une interface d'adresse publique 203.0.113.1 reliée à Internet.

Partie A

Le gérant veut faire installer une troisième borne de commande dans le café 1.

1. Indiquer les deux seules adresses IP valides pour cette nouvelle borne, parmi les quatre adresses IP proposées : (a) 192.168.20.2 — (b) 192.168.20.157 — (c) 192.168.20.261 — (d) 192.168.24.10.

L'adresse de diffusion (ou de broadcast) est la dernière adresse disponible à l'intérieur d'un réseau local.

2. Déterminer l'adresse de diffusion du réseau du café 1.

3. Déterminer combien de machines informatiques il est encore possible de connecter au réseau du café 1 après l'installation de la troisième borne de commande.

Le réseau local du café 1 n'a pas besoin de plus de 8 adresses IP différentes (ce décompte inclut les adresses réservées : adresse de diffusion et adresse réseau). Il est rappelé que la longueur du masque de sous-réseau est actuellement de 24 bits (3 octets).

4. Expliquer quelle est la longueur maximale du masque de sous-réseau que l'on pourrait choisir pour le réseau local du café 1.

Partie B

RIP (Routing Information Protocol) est un protocole de routage utilisé dans les réseaux IP. Un « saut » correspond au transfert des données d'un routeur à un autre : RIP utilise le nombre de sauts comme critère principal du coût d'un chemin — le chemin le plus optimal est celui qui traverse le moins de routeurs.

La table de routage du routeur 2 est :

Réseau destinationInterface de sortieProchain routeurNombre de sauts
192.168.20.0192.168.20.1aucun0
172.16.3.0172.16.3.1aucun0
172.16.4.0172.16.4.1aucun0
192.168.10.0172.16.3.1172.16.3.22
172.16.0.0172.16.4.1172.16.4.21
172.16.2.0172.16.4.1172.16.4.21
192.168.30.0………
172.16.1.0………

5. Recopier et compléter les deux dernières lignes de la table de routage du routeur 2.

La table de routage du routeur 2 contient un réseau de destination pour lequel deux routes différentes sont possibles : la ligne correspondante aurait donc pu être remplie différemment tout en respectant le protocole RIP.

6. Identifier ce réseau de destination et indiquer comment cette ligne de la table de routage pourrait être modifiée.

Une adresse IP qui n'est pas référencée dans la table de routage doit être routée par défaut vers Internet.

7. Recopier et compléter la ligne à ajouter à la table de routage du routeur 2 :

Réseau destinationInterface de sortieProchain routeur
autre……

Partie C

OSPF est également un protocole d'échange de données entre les routeurs, qui prend en compte le coût des routes. Le coût est lié au débit des liaisons par la formule coût = 10^9 / débit (débit exprimé en bit.s⁻¹).

8. Recopier et compléter la dernière colonne du tableau des coûts :

Type de connexionDébit en bit.s⁻¹coût
Ethernet10 Mbit.s−1=107 bit.s−110\,Mbit.s^{-1} = 10^7\ bit.s^{-1}100
Fast Ethernet100 Mbit.s−1=108 bit.s−1100\,Mbit.s^{-1} = 10^8\ bit.s^{-1}…
Fibre optique1 Gbit.s−1=109 bit.s−11\,Gbit.s^{-1} = 10^9\ bit.s^{-1}…

9. En utilisant les types de liaison décrits plus haut (fibre optique entre les routeurs 4 et 3, Ethernet entre les routeurs 4 et 1, Ethernet entre les routeurs 1 et 3, Fast Ethernet entre les routeurs 1 et 2, Fast Ethernet entre les routeurs 3 et 2), déterminer la route dont le coût est minimal pour aller du routeur 1 jusqu'au routeur 4, et calculer son coût au sens du protocole OSPF.

Partie D

Le but de cette partie est de classer les adresses IP des différents réseaux afin de faciliter leur recherche.

La fonction ip_bin prend en argument une chaîne de caractères décrivant une adresse IP en notation décimale, et renvoie une chaîne de caractères, de longueur 35 (32 bits et les 3 points), décrivant l'adresse IP en notation binaire. Exemple : ip_bin('192.168.10.1') renvoie '11000000.10101000.00001010.00000001'.

10. Donner la chaîne de caractères renvoyée par ip_bin('192.168.20.12').

La fonction precede prend en paramètres deux adresses IP en notation binaire, sous forme de chaînes identiques à celles renvoyées par ip_bin, et renvoie un booléen valant True si la première adresse précède la seconde. Exemple : avec a = '11000000.10101000.00001010.00000001' et b = '11000000.10101000.00001111.00000001', precede(a, b) renvoie True.

L'algorithme compare bit à bit les deux chaînes binaires, en lisant de gauche à droite ; dans l'exemple ci-dessus, tous les caractères sont identiques jusqu'au sixième caractère du troisième octet, où le bit de a est inférieur à celui de b, d'où la conclusion. Si la première adresse ne précède pas la seconde, la fonction doit renvoyer False.

def precede(ip_1, ip_2):
    for i in range(35):
        if ip_1[i] < ip_2[i]:
            return ...
        elif ip_1[i] > ip_2[i]:
            return ...
    return ...

11. Expliquer dans quel cas la fonction precede exécutera la dernière instruction return (celle de la ligne 7, hors de la boucle).

12. Recopier et compléter les lignes 4, 6 et 7 du code de la fonction precede.

Les tables de routage de chaque routeur sont implémentées sous la forme d'un arbre binaire de recherche, avec la classe Abr :

class Abr:
    def __init__(self, adresse_ip, interface, passerelle, cout):
        self.adresse_ip = adresse_ip
        self.interface = interface
        self.passerelle = passerelle
        self.cout = cout
        if adresse_ip != '':
            self.gauche = Abr('', '', '', 0)
            self.droite = Abr('', '', '', 0)
 
    def est_vide(self):
        return ...

Dans cette représentation : adresse_ip désigne l'adresse IP de la destination ; interface désigne l'interface réseau ; passerelle désigne l'adresse IP du prochain routeur ; cout désigne le nombre de sauts pour atteindre la destination. Par convention, l'arbre binaire vide est une instance de Abr pour laquelle adresse_ip est une chaîne vide. Un arbre binaire de recherche non vide possède nécessairement un sous-arbre gauche et un sous-arbre droite, éventuellement vides, qui sont eux-mêmes des arbres binaires de recherche : si le sous-arbre gauche n'est pas vide, l'adresse IP du sous-arbre gauche précède celle de l'instance parent ; si le sous-arbre droit n'est pas vide, l'adresse IP de l'instance parent précède celle du sous-arbre droit.

13. Citer un attribut et citer une méthode de la classe Abr.

14. Recopier et compléter la ligne return ... du code de la méthode est_vide.

15. Justifier, en mobilisant des connaissances de cours, l'intérêt qu'il peut y avoir à représenter la table de routage par un arbre binaire de recherche.

La méthode modifie (incluse dans la classe Abr) est donnée ci-dessous :

def modifie(self, adresse_ip, interface, passerelle, cout):
    if self.est_vide():
        self.adresse_ip = adresse_ip
        self.interface = interface
        self.passerelle = passerelle
        self.cout = cout
        self.gauche = Abr('', '', '', 0)
        self.droite = Abr('', '', '', 0)
    else:
        self.adresse_ip = adresse_ip
        self.interface = interface
        self.passerelle = passerelle
        self.cout = cout

Les quatre affectations du bloc if (self.adresse_ip = ... à self.cout = ...) sont exactement les mêmes que celles du bloc else.

16. Réécrire le code de la fonction modifie en évitant cette répétition.

La classe Abr est complétée afin de permettre l'ajout de nouvelles lignes à la table de routage, tout en conservant les propriétés d'un arbre binaire de recherche :

def rechercher(self, adresse_ip):
    if self.est_vide() or adresse_ip == self.adresse_ip:
        return self
    elif precede(...):
        return self.gauche.rechercher(adresse_ip)
    else:
        return self.droite.rechercher(adresse_ip)
 
def inserer(self, adresse_ip, interface, passerelle, cout):
    destination = self.rechercher(adresse_ip)
    destination.modifie(adresse_ip, interface, passerelle, cout)

On rappelle que la fonction precede prend en arguments des adresses IP écrites sous forme binaire.

17. Recopier et compléter la ligne elif precede(...): du code de la fonction rechercher.

Corrigé

Corrigé réservé aux abonnés Premium.

Créez un compte gratuit : votre première correction est offerte.

Sujet officiel du baccalauréat, épreuve de spécialité NSI. Corrigé rédigé pour ce site.