Tous les sujets du Bac 2026 · Toutes les annales du Bac de Numérique et Sciences Informatiques
Sujet du Bac Numérique et Sciences Informatiques 2026 · Asie Jour 1
Sujet du Bac de Numérique et Sciences Informatiques 2026, Asie Jour 1 : 7 exercices corrigés. Thèmes : Structures de données abstraites. Gratuit.
Thèmes du sujet : Structures de données abstraites : listes, piles, files, dictionnaires · Programmation orientée objet : classes, attributs, méthodes · Bases de données relationnelles, SGBD et langage SQL · Réseaux : adressage IP et sous-réseaux · Protocoles de routage : RIP et OSPF · Coût des algorithmes, tris et recherche
Exercice 1 - Bases de données relationnelles et S… · Bases de données relationnelles, SGBD et langage SQL
Partie B
Jessica a en charge d’amener les costumes et accessoires pour les représentations. Afin de minimiser les allers-retours, elle essaie d’optimiser le chargement de son véhicule à l’aide d’un programme.
Pour chaque représentation, elle a récupéré les informations utiles sous forme d’un dictionnaire de dictionnaires. Les sous-dictionnaires contiennent le nombre d’éléments nécessaires, le volume unitaire ainsi que le poids unitaire. Par exemple:
dmateriel = {
'costume_A': {'nb': 3, 'volume': 2, 'poids': 1},
'costume_B': {'nb': 1, 'volume': 6, 'poids': 2},
'chaise_bois': {'nb': 40, 'volume': 50, 'poids': 4},
'chapeau_A': {'nb': 2, 'volume': 3, 'poids': 1},
'chapeau_B': {'nb': 4, 'volume': 7, 'poids': 1},
}
Exercice 1 (6 points)
Cet exercice porte sur les bases de données, la programmation de base en Python et l'algorithmique.
La compagnie de danse L'air de l'art fait des présentations de spectacle. Les danseurs et danseuses d'un spectacle se déplacent donc dans une camionnette avec le matériel nécessaire.
Pour gérer la logistique, Jessica, la secrétaire de la compagnie, a mis en place une base de données.
Partie A
La base de données permet à Jessica de relier les danseurs aux différentes chorégraphies et représentations. Pour simplifier, seules les villes seront mentionnées dans les adresses.
La base de données se schématise comme suit:
La table personne est composée d'un identifiant id, d'un nom, d'une adresse et du code postal associé codep.
La table spectacle est composée d'un identifiant id, d'un jour de représentation (au format AAAA-MM-JJ), d'une adresse du lieu, de son code postal associé codep et du titre de spectacle titre.
La table choregraphie est composée d'un nomchore unique, d'une annee de création et de l'identifiant de son choregraphe.
La table participe associe une personne qui danse idpersonne, un spectacle idspectacle et une chorégraphie idchoregraphie. La clef primaire est le triplet idpersonne, idspectacle et idchoregraphie.
Les clefs primaires sont soulignées et les clefs étrangères sont précédées du symbole «#».
On pourra utiliser les mots clefs du langage SQL suivants: SELECT, DISTINCT, FROM, WHERE, JOIN... ON, UPDATE... SET, DELETE, INSERT INTO... VALUES.
La fonction d'agrégation COUNT() permet de compter le nombre d'enregistrements dans une table. Par exemple, la requête SQL ci-dessous permet de connaitre le nombre de lignes dans la table ma_table:
SELECT COUNT(*) FROM ma_table;
Un code postal est composé de cinq chiffres.
1.
Écrire une requête qui ajoute la chorégraphie 'Tout autour' de Rachid Ouramdane (id n°9) datant de 2015 à la table choregraphie.
2.
Écrire une requête qui affiche le nombre de chorégraphies de 1983.
3.
Décrire par une phrase le résultat obtenu lors de l'exécution de la requête ci-dessous:
SELECT choregraphie.nomchore, personne.nom
FROM choregraphie
JOIN personne
ON choregraphie.choregraphe = personne.id;
4.
Écrire une requête qui affiche le nom des danseurs ayant dansé dans le spectacle ayant pour titre 'Tout autour'.
5.
Préciser les précautions à prendre pour supprimer un spectacle de la table spectacle. On ne demande pas d'écrire la requête.
Exercice 1 - Structures de données et programmati… · Structures de données abstraites : listes, piles, files, dictionnaires
Partie B
Jessica a en charge d’amener les costumes et accessoires pour les représentations. Afin de minimiser les allers-retours, elle essaie d’optimiser le chargement de son véhicule à l’aide d’un programme.
Pour chaque représentation, elle a récupéré les informations utiles sous forme d’un dictionnaire de dictionnaires. Les sous-dictionnaires contiennent le nombre d’éléments nécessaires, le volume unitaire ainsi que le poids unitaire. Par exemple:
dmateriel = {
'costume_A': {'nb': 3, 'volume': 2, 'poids': 1},
'costume_B': {'nb': 1, 'volume': 6, 'poids': 2},
'chaise_bois': {'nb': 40, 'volume': 50, 'poids': 4},
'chapeau_A': {'nb': 2, 'volume': 3, 'poids': 1},
'chapeau_B': {'nb': 4, 'volume': 7, 'poids': 1},
}
6.
Recopier et compléter la ligne 3 du code ci-dessous afin que n soit égal au nombre total d'éléments nécessaires dans le dictionnaire dmateriel.
Avec l'exemple précédent, à la fin de l'exécution du script, n doit valoir: .
1 n = 0
2 for clef in dmateriel:
3 n += dmateriel[...] [...]
7.
Afin d'obtenir deux tableaux (de type list), l'un avec les clefs, l'autre avec les volumes associés, Jessica a écrit la fonction suivante:
1 def tab_clefs_tab_volumes(dmatos):
2 tab_clefs = []
3 tab_volumes = []
4 for clef, dico in dmatos.items():
5 tab_clefs.append(...)
6 tab_volumes.append(...)
7 return tab_clefs, tab_volumes
L'appel tab_clefs_tab_volumes(dmateriel) devra renvoyer le tuple:
(['costume_A', 'costume_B', 'chaise_bois', 'chapeau_A', 'chapeau_B'], [2, 6, 50, 3, 7])
Recopier et compléter les lignes 5 et 6 pour rendre effective cette fonction.
10.
Jessica a commencé à coder une fonction remplissage, qui prend en paramètres un dictionnaire dmatos contenant le matériel, un entier vmax, qui renvoie la liste des éléments à charger dans une voiture sans dépasser le volume maximal vmax et qui modifie dmatos en mettant à jour le nombre d'éléments restants.
1 def remplissage(dmatos, vmax):
2 vol = 0
3 clefs_triees = clefs_triees_selon_volume(dmatos)
4 i = len(clefs_triees) - 1
5 elements = []
6 while i >=... and vol <...:
7 clef = clefs_triees[i]
8 if dmatos[clef]['nb'] == 0:
9 i -= 1
10 elif vol + dmatos[clef]['volume'] <= vmax:
11 vol +=...
12 elements.append(...)
13 dmatos[clef]['nb'] -= 1
14 else:
15...
16 return elements
Recopier et compléter les lignes 6 et de 11 à 15 de la fonction remplissage ci-dessus:
11.
On remarquera que la fonction remplissage renvoie une liste vide s'il n'y a plus de matériel à charger dans dmatos (les valeurs associées à 'nb' sont toutes égales à 0).
Écrire une fonction nb_voitures qui prend en paramètres un dictionnaire dmatos contenant le matériel, un entier vmax et renvoie le nombre de voitures nécessaires pour charger l'ensemble du matériel (on supposera que toutes les voitures ont la même capacité vmax). On pourra faire appel à la fonction remplissage, même si le code n'a pas été complété.
Exercice 1 - Algorithmes et complexité · Coût des algorithmes, tris et recherche
Partie B
Jessica a en charge d’amener les costumes et accessoires pour les représentations. Afin de minimiser les allers-retours, elle essaie d’optimiser le chargement de son véhicule à l’aide d’un programme.
Pour chaque représentation, elle a récupéré les informations utiles sous forme d’un dictionnaire de dictionnaires. Les sous-dictionnaires contiennent le nombre d’éléments nécessaires, le volume unitaire ainsi que le poids unitaire. Par exemple:
dmateriel = {
'costume_A': {'nb': 3, 'volume': 2, 'poids': 1},
'costume_B': {'nb': 1, 'volume': 6, 'poids': 2},
'chaise_bois': {'nb': 40, 'volume': 50, 'poids': 4},
'chapeau_A': {'nb': 2, 'volume': 3, 'poids': 1},
'chapeau_B': {'nb': 4, 'volume': 7, 'poids': 1},
}
8.
Pour optimiser le volume chargé dans son véhicule, Jessica se dit qu'une bonne stratégie serait de remplir son véhicule du matériel le plus volumineux en premier puis de finir de le remplir par du petit matériel.
Préciser à quel type d'algorithme vu en cours cette stratégie fait référence.
9.
Pour le moment, on suppose que la fonction clefs_triees_selon_volume prend en paramètre un dictionnaire dmatos contenant le matériel et renvoie la liste des clefs de dmatos triée dans l'ordre croissant des volumes unitaires associés à chacune des clefs. Ainsi on a:
>>> clefs_triees_selon_volume(dmateriel)
['costume_A', 'chapeau_A', 'costume_B', 'chapeau_B', 'chaise_bois']
Citer un algorithme de tri vu en cours et donner un ordre de grandeur de son coût en temps d'exécution en fonction de la taille de la liste à trier.
Exercice 2 - Programmation orientée objet · Programmation orientée objet : classes, attributs, méthodes
Exercice 2 (6 points)
Cet exercice porte sur les thèmes langages, programmation et algorithmique.
Dans le cadre d’un concours national intitulé “Jeunes Talents IA 2025”, une équipe constituée d’élèves de terminale NSI est sélectionnée pour développer un système d’intelligence artificielle capable de détecter si un email est un spam ou non pour la messagerie d’un établissement scolaire. Après réflexion, l’équipe décide d’utiliser un perceptron pour classer les messages comme spam ou non spam.
Le perceptron est un neurone artificiel qui imite très simplement le fonctionnement d’un neurone biologique. L’équipe choisit d’entraîner le perceptron à l’aide d’un algorithme d’apprentissage supervisé: on présente au perceptron des exemples, avec les bonnes réponses, afin qu’il ajuste automatiquement ses poids dans le but d’améliorer ses prédictions.
Le fonctionnement d’un perceptron est décrit ci-après:
Le perceptron dispose d’un tuple de poids et d’un biais . Il reçoit en entrée un tuple de valeurs numériques d’entrée .
Il calcule la somme pondérée avec biais des valeurs d’entrées:
Puis il applique une fonction d’activation. Dans cet exercice la fonction d’activation est la fonction seuil qui renvoie 1 si la somme pondérée avec biais est supérieure ou égale à 0, et 0 sinon.
Le schéma ci-dessus illustre le cas .
Pour commencer, l’équipe considère un perceptron à deux entrées ayant pour caractéristiques les poids et , et un biais .
Voici le début d’une classe DetecteurSpam basée sur un perceptron:
class DetecteurSpam:
def __init__(self, nb_entrees):
self.biais = 0.0
self.poids = [0.0 for i in range(nb_entrees)]
def get_biais(self):
return self.biais
def set_biais(self, nouveau_biais):
self.biais = nouveau_biais
def get_poids(self):
return self.poids
def set_poids(self, nouveaux_poids):
assert len(nouveaux_poids) == len(self.poids)
self.poids = nouveaux_poids
1.
Calculer la valeur somme de la somme pondérée avec biais du perceptron lorsque les valeurs d'entrée sont et et en déduire la valeur de sortie sortie du perceptron si la fonction d'activation est la fonction seuil (sortie à 1 si somme supérieure ou égale à 0, sinon 0).
2.
Donner le nom d'une méthode et le nom d'un attribut de cette classe.
3.
Donner une suite d'instructions Python permettant de créer un objet detecteur (instance de la classe DetecteurSpam) correspondant à un détecteur à deux entrées, puis de remplacer ses poids et son biais par les valeurs , et en utilisant les méthodes de la classe.
4.
Expliquer le rôle de la ligne 16 du code ( assert len(nouveaux_poids) == len(self.poids)).
5.
Écrire la méthode fonction_activation qui prend en paramètre valeur un nombre et qui renvoie 1 si valeur est supérieur ou égal à 0, et 0 sinon.
6.
Recopier et compléter la méthode prediction.
def prediction(self, entrees):
somme = 0
for i in range(len(entrees)):
somme +=...
somme +=...
sortie = self.fonction_activation(...)
return...
8.
Un des membres de l'équipe propose les listes echantillon et cibles suivantes pour tester la méthode entrainement:
echantillon = [[0.5, 0.3], [0.2, 0.1], [0.4, 0.8], [0.7, 0.9]]
cibles = [0, 1, 1, 1]
Donner les valeurs de echantillon[1] et echantillon[2][1].
9.
Recopier et compléter les lignes 5, 7, 8 et 13 du code de la méthode entrainement.
10.
L'équipe veut maintenant créer un détecteur de spam à 2 caractéristiques d'entrée et l'entraîner sur les données du tableau ci-dessous pour apprendre à détecter les emails avec "URGENT" ET "GRATUIT".
Contient "URGENT" ?
Contient "GRATUIT" ?
Est un SPAM ?
0 (non) · 0 (non) · 0 (non)
0 (non) · 1 (oui) · 0 (non)
1 (oui) · 0 (non) · 0 (non)
1 (oui) · 1 (oui) · 1 (oui)
Écrire un programme permettant de créer et d'entraîner le détecteur sur les listes emails = [[0, 0], [0, 1], [1, 0], [1, 1]] et spams = [0, 0, 0, 1] pendant au maximum 1000 époques, puis d'afficher dans la console le nombre d'époques nécessaires pour que le détecteur ne fasse plus d'erreurs (si c'est possible), et -1 sinon.
Exercice 2 - Coût d'exécution · Coût des algorithmes, tris et recherche
Exercice 2 (6 points)
Cet exercice porte sur les thèmes langages, programmation et algorithmique.
Dans le cadre d’un concours national intitulé “Jeunes Talents IA 2025”, une équipe constituée d’élèves de terminale NSI est sélectionnée pour développer un système d’intelligence artificielle capable de détecter si un email est un spam ou non pour la messagerie d’un établissement scolaire. Après réflexion, l’équipe décide d’utiliser un perceptron pour classer les messages comme spam ou non spam.
Le perceptron est un neurone artificiel qui imite très simplement le fonctionnement d’un neurone biologique. L’équipe choisit d’entraîner le perceptron à l’aide d’un algorithme d’apprentissage supervisé: on présente au perceptron des exemples, avec les bonnes réponses, afin qu’il ajuste automatiquement ses poids dans le but d’améliorer ses prédictions.
Le fonctionnement d’un perceptron est décrit ci-après:
Le perceptron dispose d’un tuple de poids et d’un biais . Il reçoit en entrée un tuple de valeurs numériques d’entrée .
Il calcule la somme pondérée avec biais des valeurs d’entrées:
Puis il applique une fonction d’activation. Dans cet exercice la fonction d’activation est la fonction seuil qui renvoie 1 si la somme pondérée avec biais est supérieure ou égale à 0, et 0 sinon.
Le schéma ci-dessus illustre le cas .
Pour commencer, l’équipe considère un perceptron à deux entrées ayant pour caractéristiques les poids et , et un biais .
Voici le début d’une classe DetecteurSpam basée sur un perceptron:
class DetecteurSpam:
def __init__(self, nb_entrees):
self.biais = 0.0
self.poids = [0.0 for i in range(nb_entrees)]
def get_biais(self):
return self.biais
def set_biais(self, nouveau_biais):
self.biais = nouveau_biais
def get_poids(self):
return self.poids
def set_poids(self, nouveaux_poids):
assert len(nouveaux_poids) == len(self.poids)
self.poids = nouveaux_poids
7.
Donner le coût d'exécution temporel de la méthode prediction en fonction de la taille des entrées.
Exercice 3 - Adressage IP et sous-réseaux · Réseaux : adressage IP et sous-réseaux
Cet exercice porte sur les protocoles de routage, la programmation orientée objet et la notion de file.
Le but de cet exercice est de simuler la façon dont des routeurs construisent leur table de routage selon le protocole RIP.
On considère à titre d’exemple le réseau ci-dessous:
Les adresses des quatre réseaux sont notées sous la forme IP/S où IP est une adresse IP donnée par quatre octets écrits en base 10 et S est un entier inférieur à 32 appelé suffixe. Une adresse IP peut être écrite sur 32 bits en binaire. Le suffixe indique que les S premiers bits de l’adresse correspondent à la partie fixe de l’adresse et les suivants à la partie propre à la machine.
Pour que deux machines soient sur un même réseau local avec un suffixe S, il faut que les S premiers bits de leurs adresses IP soient identiques.
Partie A
1.
Identifier la partie fixe des adresses IP des machines branchées dans le réseau 192.168.20.0/24.
2.
Dans chaque réseau, il y a deux adresses réservées. Donner le nombre maximum de machines qui peuvent être branchées dans un réseau dont le suffixe est 30.
Partie B
Afin de comparer les adresses IP pour savoir si elles appartiennent à un même réseau, on calcule le masque de réseau à partir du suffixe. Les premiers bits, correspondant à la partie fixe, sont mis à 1 et les autres sont mis à 0.
4.
Donner le tuple d'entiers correspondant à un masque pour un réseau dont le suffixe est 30.
Pour isoler la partie fixe d'une adresse IP, on utilise le ET bit à bit. Cela consiste à appliquer l'opération booléenne ET à tous les bits se trouvant à la même position dans les deux nombres écrits en binaire.
01110110 (118)
ET 11010010 (210)
-----------
01010010 (82)
En Python, il est possible de faire cette opération en utilisant l'opérateur & directement entre deux nombres écrits en base 10:
>>> 118 & 210
82
5.
Expliquer pourquoi 255 & A est égal à A, si A est un entier compris entre 0 et 255.
6.
Déterminer, en justifiant la réponse, si (172, 20, 189, 8) et (172, 20, 191, 203) sont dans un même réseau dont le masque est (255, 255, 252, 0).
7.
La fonction meme_reseau prend en paramètres trois tuples de quatre entiers adresse1, adresse2 et masque, et renvoie un booléen indiquant si adresse1 et adresse2 sont dans le même réseau en utilisant le masque de réseau masque.
Recopier et compléter le code de la fonction meme_reseau:
def meme_reseau(adresse1, adresse2, masque):
for i in range(4):
octet1 = adresse1[...] & masque[...]
octet2 =...
if...:
return...
return...
Exercice 3 - Protocoles de routage : RIP · Protocoles de routage : RIP et OSPF
Cet exercice porte sur les protocoles de routage, la programmation orientée objet et la notion de file.
Le but de cet exercice est de simuler la façon dont des routeurs construisent leur table de routage selon le protocole RIP.
On considère à titre d’exemple le réseau ci-dessous:
Les adresses des quatre réseaux sont notées sous la forme IP/S où IP est une adresse IP donnée par quatre octets écrits en base 10 et S est un entier inférieur à 32 appelé suffixe. Une adresse IP peut être écrite sur 32 bits en binaire. Le suffixe indique que les S premiers bits de l’adresse correspondent à la partie fixe de l’adresse et les suivants à la partie propre à la machine.
Pour que deux machines soient sur un même réseau local avec un suffixe S, il faut que les S premiers bits de leurs adresses IP soient identiques.
Partie A (suite): Table de routage RIP manuelle
Le protocole RIP permet de minimiser la distance, c'est-à-dire le nombre de routeurs traversés par un paquet de données. Voici la table de routage du routeur R1 dans le réseau représenté sur la figure 1, selon le protocole RIP:
Table de routage de R1
Destination
Interface
Passerelle
Distance
192.168.20.0/24
192.168.20.254
-
0
172.24.0.0/30
172.24.0.1
-
0
172.24.1.0/30
172.24.0.1
172.24.0.2
1
192.168.40.0/24
172.24.0.1
172.24.0.2
2
3.
Donner la table de routage du routeur R2 pour le réseau représenté sur la figure 1, selon le protocole RIP.
Table de routage de R2
Destination
Interface
Passerelle
Distance
192.168.20.0/24
172.24.0.0/30
172.24.1.0/30
192.168.40.0/24
Partie C: Simulation orientée objet de Bellman-Ford
On dispose d'une classe File qui permet d'instancier une file (avec méthodes enfiler(e), defiler() et est_vide()). Chaque réseau local est modélisé à l'aide de la classe Reseau:
class Reseau:
def __init__(self, adresse, masque):
self.adresse = adresse
self.masque = masque
self.machines = {}
self.file = File()
Un paquet est un couple de la forme (orig, donnees). La méthode diffuser traite les paquets de sa file et les dépose dans les files des machines destinataires (toutes sauf l'émetteur).
8.
Recopier et compléter le code de la méthode diffuser:
def diffuser(self):
while not...:
paquet =...
orig, donnees = paquet
for m in self.machines:
if...:
self.machines[m].enfiler(...)
La classe Routeur gère les interfaces et la table de routage, représentée par un dictionnaire associant à chaque adresse réseau un triplet (i_interf, passerelle, distance). Lorsqu'il est directement connecté, on met None à la place de la passerelle.
>>> routeur_m.table
{(172, 64, 0, 0): (1, None, 0),
(172, 60, 0, 0): (0, (172, 58, 0, 2), 1),
(192, 168, 47, 0): (0, (172, 58, 0, 2), 2),
(172, 62, 0, 0): (0, (172, 58, 0, 2), 2)}
vecteurs = [((192, 168, 72, 0), 0), ((172, 62, 0, 0), 0),
((172, 64, 0, 0), 0), ((172, 60, 0, 0), 1),
((192, 168, 47, 0), 1)]
9.
Déterminer la valeur de routeur_m.table après l'appel routeur_m.m_a_j((172, 64, 0, 2), 1, vecteurs):
10.
Recopier et compléter les lignes 4 et 6 du code de la méthode m_a_j:
1 def m_a_j(self, passerelle, i_interf, vecteurs):
2 a_ete_modif = False
3 for adresse, d in vecteurs:
4 if... or...:
5 self.table[adresse] = (i_interf, passerelle, d+1)
6 a_ete_modif =...
7 if a_ete_modif:
8 self.envoyer_vecteurs(i_interf)
11.
Recopier et compléter les lignes 5 et 6 du code de la méthode vecteurs:
1 def vecteurs(self, i):
2 res = []
3 for adresse in self.table:
4 i_interf, passerelle, dist = self.table[adresse]
5 if...:
6 res.append(...)
7 return res
12.
Recopier et compléter les lignes 3 à 7 du code de la méthode envoyer_vecteurs:
1 def envoyer_vecteurs(self, i_interf):
2 for i in range(len(self.interfaces)):
3 if...:
4 adresse = self.interfaces[i].adresse
5 v = self.vecteurs(...)
6 paquet = (adresse, v)
7....enfiler(paquet)
13.
Recopier et compléter la suite du script ci-dessous à partir de la ligne 4 afin de construire les tables de routage des routeurs contenus dans le tableau routeurs suivant l'algorithme:
1 for routeur in routeurs:
2 routeur.envoyer_vecteurs(-1)
3
4 continuer = True
5 while continuer:
6...
Tu peux aussi réviser par thème
Entraîne-toi sur un thème avec les exercices des sujets de toutes les années.
- Bases de données relationnelles, SGBD et langage SQL · 10 exercices · 70 % de chances de tomber
- Structures de données abstraites : listes, piles, files, dictionnaires · 8 exercices · 60 % de chances de tomber
- Programmation orientée objet : classes, attributs, méthodes · 6 exercices · 50 % de chances de tomber
- Protocoles de routage : RIP et OSPF · 4 exercices · 45 % de chances de tomber
- Récursivité · 4 exercices · 40 % de chances de tomber
- Graphes : modélisation, implémentations et parcours · 3 exercices · 40 % de chances de tomber