Baccalauréat — Centres étrangers (groupe 1, probable) J1 — 2024 — NSI
Bac NSI 2024 — Centres étrangers (groupe 1) — Jour 1
Sujet
Sujet officiel du baccalauréat général, épreuve d'enseignement de spécialité numérique et sciences informatiques, session 2024, jour 1 (code sujet 24-NSIJ1G11, probablement Centres étrangers groupe 1). Durée 3 heures 30, calculatrice non autorisée. 3 exercices indépendants, tous à traiter.
Note de source : le sujet original numérisé (scan) porte des annotations manuscrites d'un candidat (réponses griffonnées, ratures). Seul le texte imprimé officiel a été repris ci-dessous.
Exercice 1 (6 points) — Python, programmation dynamique, graphes et réseaux
On lutte contre un virus informatique qui se propage en migrant régulièrement vers un autre ordinateur, en choisissant au hasard sa nouvelle cible parmi les ordinateurs accessibles. On veut savoir quels ordinateurs protéger pour lutter le plus efficacement possible avec des ressources limitées.
Le réseau comprend 5 ordinateurs numérotés 0 à 4, avec les liaisons suivantes : 0 est relié à 1, 2, 3 et 4 ; 1 est de plus relié à 2 et à 3.
1. On représente ce réseau par un graphe stocké sous forme de listes de voisins. Compléter la définition de voisins :
voisins = [[1, 2, 3, 4],
[0, 2, 3],
[0, 1],
[...],
[...]]On ajoute un sixième ordinateur, numéroté 5, accessible seulement depuis les ordinateurs 0 et 2.
2. Dessiner (décrire) le nouveau graphe.
3. Donner la nouvelle définition de voisins.
4. Compléter la fonction voisin_alea(voisins, s), qui renvoie un voisin de s choisi aléatoirement (on pourra utiliser random.randrange(n), qui renvoie un entier aléatoire entre 0 inclus et n exclu) :
def voisin_alea(voisins, s):
return ...On donne :
def marche_alea(voisins, i, n):
if n == 0:
return i
return marche_alea(voisins, voisin_alea(voisins, i), n-1)5. Justifier que marche_alea est une fonction récursive.
6. Décrire ce que modélise cette fonction, en rapport avec le contexte de l'exercice.
7. Compléter la fonction simule, qui simule n_tests fois le déplacement d'un virus pendant n_pas étapes, démarrant au sommet i, et qui renvoie une liste contenant en position j le nombre de fois que le virus a terminé son parcours au sommet j, divisé par n_tests :
def simule(voisins, i, n_tests, n_pas):
results = [0] * len(voisins)
...
return ...8. L'appel simule(voisins, 4, 1000, 1000) (sur le réseau à 6 ordinateurs) renvoie [0.328, 0.195, 0.18, 0.12, 0.059, 0.118]. Déduire de ce résultat l'ordinateur du réseau le plus rentable à protéger.
Au début, le virus n'est présent que sur un ordinateur. À chaque étape, il contamine tous ses voisins non déjà contaminés. On cherche le temps que met le virus à se propager à tout le réseau.
9. Un graphe voisins représente un réseau, et s un sommet de départ. Proposer un algorithme pour déterminer le temps, en étapes, que met un virus à se propager dans l'intégralité d'un réseau.
Exercice 2 (6 points) — Réseaux et protocoles de routage
Une adresse IPv4 (32 bits) est notée en 4 octets a.b.c.d (« notation décimale pointée »). La notation a.b.c.d/n (CIDR) signifie que les n premiers bits représentent la partie « réseau », les bits restants la partie « machine ». L'adresse dont tous les bits « machine » sont à 0 est l'« adresse du réseau » ; celle dont ils sont tous à 1 est l'« adresse de diffusion ».
On considère un réseau reliant deux réseaux locaux L1 et L2 par l'intermédiaire de 8 routeurs (A à H). Le réseau local L1 utilise un masque de sous-réseau sur 24 bits (255.255.255.0) ; le réseau local L2 utilise un masque de sous-réseau sur 16 bits, avec des adresses de la forme 172.16.x.x.
Partie A : adresses IP
1. Donner le masque de sous-réseau des machines de L2, en notation décimale pointée.
Concernant L2 :
2. Donner l'adresse du réseau. 3. Donner l'adresse de diffusion. 4. Donner le nombre maximum de machines pouvant être connectées à ce réseau.
Partie B : protocoles de routage
Extraits des tables de routage des 8 routeurs (règle vers L2 uniquement) :
| Routeur | Réseau destinataire | Passerelle |
|---|---|---|
| A | L2 | (adresse du routeur H sur la liaison A–H) |
| B | L2 | (adresse du routeur C sur la liaison B–C) |
| C | L2 | (adresse du routeur D sur la liaison C–D) |
| D | L2 | Connecté (D est directement relié au réseau local L2) |
| E | L2 | (adresse du routeur D sur la liaison E–D) |
| F | L2 | (adresse du routeur E sur la liaison F–E) |
| G | L2 | (adresse du routeur H sur la liaison G–H) |
| H | L2 | (adresse du routeur D sur la liaison H–D) |
5. À l'aide des tables de routage, donner un chemin (nommer les routeurs traversés) suivi par un message envoyé de L1 vers L2.
La liaison entre les routeurs H et D est rompue.
6. Sachant que le protocole de routage RIP est utilisé (distance en nombre de sauts), donner les nouveaux chemins que pourra suivre un message allant de L1 vers L2. 7. Choisir un des chemins de la question précédente. Donner les routeurs dont la règle de routage à destination de L2 est obligatoirement modifiée, et écrire les nouvelles règles.
La liaison H–D est rétablie. Pour tenir compte du débit des liaisons, on utilise désormais le protocole OSPF (distance liée au coût des liaisons), avec (BP : bande passante en bit/s).
Bandes passantes des liaisons du réseau : A–B, A–H, A–G, B–C, C–D, F–H, G–H : 1 Gbit/s ; C–H, D–H : 100 Mbit/s ; D–E, E–F, F–G : 10 Gbit/s.
8. Calculer le coût des liaisons pour les 3 valeurs de bande passante présentes ci-dessus. 9. Déterminer le chemin que suivra un message allant de L1 vers L2, et donner son coût. 10. La liaison entre les routeurs G et F est rompue. Déterminer le nouveau chemin suivi par un message allant de L1 vers L2, et donner son coût.
Exercice 3 (8 points) — Python, programmation orientée objet, bases de données relationnelles et SQL
L'objectif est de faciliter la gestion du système d'information d'un camping municipal, dont les informations sont stockées dans une base de données relationnelle à trois relations.
Client(id_client, nom, prenom, adresse, ville, pays, telephone)
Reservation(id_reservation, #id_client, #id_emplacement, nombre_personne, date_arrivee, date_depart)
La troisième relation, Emplacement, contient tous les emplacements du camping. Extrait :
| id_emplacement | nom | localisation | tarif_journalier |
|---|---|---|---|
| 1 | myrtille | A4 | 25 |
| 2 | mirabelle | D1 | 35 |
| 3 | mangue | B2 | 29.90 |
| 4 | mandarine | B1 | 25 |
| 5 | mûre | C3 | 29.90 |
| 6 | melon | A2 | 25 |
Partie A
1. Citer deux avantages à utiliser une base de données relationnelle plutôt qu'un fichier texte ou tableur.
2. Quelle doit être la caractéristique d'un attribut pour pouvoir être utilisé comme clé primaire ?
3. Dans Reservation, quel est le rôle des clés étrangères id_client et id_emplacement ?
4. Donner le schéma relationnel de Emplacement, en précisant la clé primaire et le type de chaque attribut.
5. À partir de l'extrait donné, donner le résultat de :
SELECT id_emplacement, nom, localisation
FROM Emplacement
WHERE tarif_journalier = 25;6. Écrire une requête donnant le nom et le prénom de tous les clients habitant à 'Strasbourg'.
7. Écrire une requête ajoutant un nouveau client : id_client 42, nom 'CODD', prénom 'Edgar', adresse '28 rue des Capucines', ville 'Lyon', pays 'France', téléphone '0555555555'.
8. Écrire une requête SQL récupérant, pour la réservation id_reservation = 18 : Client.nom, Client.prenom, Reservation.nombre_personne, Reservation.date_arrivee, Reservation.date_depart, Emplacement.tarif_journalier.
Partie B
On veut éditer une facture correspondant au séjour d'un client, à partir d'un tuple de trois objets des classes Client, Reservation et Emplacement (récupérés depuis la base de données, à la manière de la question 8) :
from datetime import datetime
class Client:
def __init__(self, nom, prenom, adresse, ville, pays, telephone):
self.nom = nom
self.prenom = prenom
self.adresse = adresse
self.ville = ville
self.pays = pays
self.telephone = telephone
class Reservation:
def __init__(self, id_reservation, nombre_personne, date_arrivee, date_depart):
self.id_reservation = id_reservation
self.nombre_personne = nombre_personne
self.date_arrivee = date_arrivee
self.date_depart = date_depart
def nb_jours(self):
"""renvoie, à l'aide de l'attribut days de la classe timedelta,
un entier correspondant au nombre de jours passés au camping."""
return (self.date_depart - self.date_arrivee).days
class Emplacement:
def __init__(self, nom, tarif_journalier):
self.nom = nom
self.tarif_journalier = tarif_journalier9. Expliquer pourquoi le terme self est utilisé comme paramètre des méthodes des classes Client, Reservation et Emplacement.
10. Instancier une variable client01 de la classe Client représentant un client se nommant CODD Edgar habitant au 28 rue des Capucines à Lyon, France, ayant pour téléphone '0555555555'.
On veut une fonction renvoyant le montant dû par un client pour un emplacement et une durée de séjour donnés, sachant qu'au tarif journalier de location il faut ajouter une taxe de séjour de 2,20 € par jour et par personne. Exemple : pour 4 personnes, 12 jours, un emplacement à 30 € la journée, 30 * 12 + 4 * 2.20 * 12 vaut 465.6.
11. Compléter la ligne 5 de montant_a_regler :
def montant_a_regler(triplet):
"""renvoie le montant en euros à régler pour cette réservation"""
client, reservation, emplacement = triplet
return ...Chaque facture possède un numéro unique, une chaîne de caractères au format 'AAAA-MMM-xxx' : 'AAAA' une année entre 2018 et 2024, 'MMM' les trois premières lettres du mois en anglais, 'xxx' trois chiffres. On écrit une fonction facture_est_valide testant si une chaîne est un numéro de facture valide. Comportement attendu : facture_est_valide('2024-MAY-230') → True ; facture_est_valide('2012-MAY-230') → False ; facture_est_valide('2024-MAI-230') → False ; facture_est_valide('2024-JUN-23') → False.
calendrier = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN',
'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC']
def separe(chaine):
"""renvoie une liste constituée de chaînes qui étaient séparées par le caractère -"""
return chaine.split('-')
def que_des_chiffres(chaine):
"""renvoie vrai si chaine n'est constituée que des caractères de 0 à 9, faux sinon"""
for car in chaine:
if not (car in "0123456789"):
return False
return True
def facture_est_valide(chaine):
"""renvoie vrai si chaine est une chaîne de caractères conforme au modèle de facture"""
partie = separe(chaine)
if not (len(partie) == 3):
return False
annee, mois, numero = partie[0], partie[1], partie[2]
if not (que_des_chiffres(annee)):
return False
if not (len(annee) == 4) or not (2018 <= annee <= 2024):
return False
# Reste à faire vérifier les mois MMM
...
# Reste à faire vérifier le numéro xxx
...
return True12. Expliquer pourquoi une erreur se produit à l'exécution de la fonction facture_est_valide donnée ci-dessus.
13. Proposer une correction du code pour que cette erreur ne se produise plus.
14. Compléter le code afin de vérifier les mois (à la place des points de suspension après le commentaire correspondant) et le numéro dans facture_est_valide. Pour chaque vérification, plusieurs lignes sont possibles.
Corrigé
Créez un compte gratuit : votre première correction est offerte.