Épreuve pratique · 2026 · Sujet 19

Bac NSI pratique 2026 sujet 19 : Réservoirs d’eau, moyennes et districts vulnérables

La commune surveille plusieurs réservoirs alimentant des districts. Chaque dictionnaire contient nom, capacite maximale en litres, volume actuellement disponible et district. Plusieurs réservoirs peuvent appartenir au même district. Le sujet distingue une pénurie individuelle, définie par un taux de remplissage sous 20%, d’une vulnérabilité relative, définie par la moyenne de volume d’un district sous 80% de la moyenne globale. Ces critères ne mesurent donc pas la même chose.

Dans ce sujet

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é.

Application

Réservoirs d’eau, moyennes et districts vulnérables

La commune surveille plusieurs réservoirs alimentant des districts. Chaque dictionnaire contient nom, capacite maximale en litres, volume actuellement disponible et district. Plusieurs réservoirs peuvent appartenir au même district. Le sujet distingue une pénurie individuelle, définie par un taux de remplissage sous 20%, d’une vulnérabilité relative, définie par la moyenne de volume d’un district sous 80% de la moyenne globale. Ces critères ne mesurent donc pas la même chose.

RéservoirCapacité (L)Volume (L)District
Nuiavai10000055000Tepua
Farepape12000045000Fare
Vaipuna8000060000Hiva Oro
Vaihere9500020000Fare
Teanavai11000090000Avera
Matavai7000025000Tepua
Anaʻitea8500030000Hiva Oro
Faaroa6000040000Avera
Vaitiare10500095000Fare
Motuavai9000010000Tepua

Le dossier comporte le sujet et les fichiers listés dans les téléchargements. Les codes de départ sont reproduits ci-dessous. Travaillez sur une copie. Les appels professeur signalés dans les questions servent à présenter votre démarche ; vous pouvez aussi demander de l’aide en cas de difficulté.

Code fourni : donnees.py
reservoirs = [
    {"nom": "Nuiavai", "capacite": 100000, "volume": 55000, "district": "Tepua"},
    {"nom": "Farepape", "capacite": 120000, "volume": 45000, "district": "Fare"},
    {"nom": "Vaipuna", "capacite": 80000, "volume": 60000, "district": "Hiva Oro"},
    {"nom": "Vaihere", "capacite": 95000, "volume": 20000, "district": "Fare"},
    {"nom": "Teanavai", "capacite": 110000, "volume": 90000, "district": "Avera"},
    {"nom": "Matavai", "capacite": 70000, "volume": 25000, "district": "Tepua"},
    {"nom": "Anaʻitea", "capacite": 85000, "volume": 30000, "district": "Hiva Oro"},
    {"nom": "Faaroa", "capacite": 60000, "volume": 40000, "district": "Avera"},
    {"nom": "Vaitiare", "capacite": 105000, "volume": 95000, "district": "Fare"},
    {"nom": "Motuavai", "capacite": 90000, "volume": 10000, "district": "Tepua"}
]
Code fourni : gestion_eau.py
# ------------------------------------
# gestion_eau.py
# Programme de contrôle des réservoirs
# ------------------------------------
from donnees import reservoirs

# Question 1 : écrire la fonction est_en_penurie


def est_en_penurie(reservoirs, nom_reservoir):
    pass

# Question 2 : écrire la fonction volume_par_district


def volume_par_district(reservoirs):
    pass

# Question 3


def volume_moyen(reservoirs):
    """
    Renvoie le volume moyen d'eau disponible dans les réservoirs.
    """
    somme_totale = 0
    for r in reservoirs:
        somme_totale += r["volume"]
    moyenne = somme_totale / (len(reservoirs)-1)
    return moyenne

# Question 4


def liste_districts(reservoirs):
    """
    Renvoie la liste des districts présents dans les données.
    """
    liste = []
    for r in reservoirs:
        if (r["district"] not in liste):
            liste.append(r["district"])
    return liste


def reservoirs_par_district(reservoirs):
    """
    Renvoie un dictionnaire associant chaque district à la liste
    des réservoirs qui s’y trouvent.
    """
    liste_rpd = {}
    for r in reservoirs:
        district = r["district"]
        if district not in liste_rpd:
            liste_rpd[district] = []
        liste_rpd[district].append(r)
    return liste_rpd


def districts_vulnerables(reservoirs):
    pass

Question 1

#

Écrire est_en_penurie(reservoirs,nom_reservoir). Le nom existe dans la liste ; renvoyer si son taux de remplissage est strictement inférieur à 20%.

Indice

Le pourcentage utilise la capacité du réservoir concerné.

Comprendre la correction
def est_en_penurie(reservoirs, nom_reservoir):
    for reservoir in reservoirs:
        if reservoir['nom'] == nom_reservoir:
            return 5 * reservoir['volume'] < reservoir['capacite']

Avec une capacité positive, volume/capacite<0.2 équivaut à 5×volume< capacite. Cette écriture garde des entiers et exprime exactement le seuil 20%. Le return se trouve seulement après avoir reconnu le nom : un autre réservoir rencontré en premier ne doit pas déterminer la réponse. Dans le fichier, Motuavai est en pénurie ; Nuiavai ne l’est pas.

assert est_en_penurie(reservoirs,'Motuavai')
assert not est_en_penurie(reservoirs,'Nuiavai')
assert not est_en_penurie([{'nom':'x','volume':20,'capacite':100}],'x')
Voir la question dans le sujet PDF, p. 3 (nouvel onglet)

Question 2

#

Écrire volume_par_district(reservoirs), qui renvoie les noms distincts de district associés au total des volumes disponibles.

Indice

Le même nom de district réapparaît plusieurs fois.

Comprendre la correction
def volume_par_district(reservoirs):
    volumes = {}
    for r in reservoirs:
        district = r['district']
        if district not in volumes:
            volumes[district] = 0
        volumes[district] += r['volume']
    return volumes
DistrictVolume total (L)
Tepua90000
Fare160000
Hiva Oro90000
Avera130000

La première rencontre crée un compteur nul, les suivantes ajoutent le volume. Affecter directement r["volume"] à chaque passage ferait disparaître les réservoirs précédents du même district. La somme des quatre totaux vaut 470000L, identique à la somme des dix volumes : cette conservation constitue un bon contrôle.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)

Question 3

#

Tester volume_moyen : exiger au moins un réservoir, vérifier que la moyenne ne dépasse pas la capacité maximale et contrôler un cas de deux volumes égaux. Corriger la fonction.

Indice

Deux valeurs identiques doivent avoir cette même valeur pour moyenne.

Comprendre la correction

Le code divise par len(reservoirs)−1 au lieu du nombre de valeurs. Avec un seul réservoir, il divise par zéro ; avec deux volumes 50, il renvoie 100 au lieu de 50. La garde d’entrée pose la précondition et le bon dénominateur restaure la moyenne.

def volume_moyen(reservoirs):
    assert len(reservoirs) > 0, 'Au moins un réservoir est nécessaire'
    somme = 0
    for r in reservoirs:
        somme += r['volume']
    return somme / len(reservoirs)
cas=[{'volume':50,'capacite':100},{'volume':50,'capacite':100}]
assert volume_moyen(cas) == 50
assert volume_moyen(cas) <= max(r['capacite'] for r in cas)
assert volume_moyen([{'volume':30,'capacite':100}]) == 30
try:
    volume_moyen([])
except AssertionError:
    pass
else:
    raise AssertionError('La liste vide doit être refusée')

La borne par la capacité maximale suppose des données cohérentes :0≤volume≤capacite. Elle est utile mais trop large pour suffire seule : une moyenne incorrecte peut rester sous cette capacité. Le test exact avec deux volumes égaux détecte directement le mauvais dénominateur. La moyenne réelle du fichier vaut 47000L.

Voir la question dans le sujet PDF, p. 3 (nouvel onglet)

Question 4

#

Avec les fonctions précédentes, liste_districts et reservoirs_par_district, écrire districts_vulnerables : identifier les districts dont le volume moyen est inférieur à 80% de la moyenne globale.

PythonComparer des moyennes, même avec des effectifs différentsÉcrivez votre solution et mettez-la à l’épreuve

Écrivez districts_vulnerables(reservoirs). La liste est non vide. Renvoyez les districts dont le volume moyen par réservoir est strictement inférieur à 80 % de la moyenne de tous les réservoirs. Les auxiliaires volume_moyen, liste_districts et reservoirs_par_district sont fournis. Gardez l’ordre de première apparition des districts.

def districts_vulnerables(reservoirs):
    # À vous de jouer
    pass

Les cas de test proposés :

  • Effectifs inégaux : La moyenne globale vaut 22,5 et le seuil 18 ; il ne faut pas moyenner les deux moyennes de district.
  • La moyenne globale doit être pondérée : La moyenne par réservoir vaut 37,5, donc le seuil est 30. Une moyenne non pondérée des districts donnerait 36 et classerait A à tort.
  • Égalité au seuil : 40 égale 80 % de 50 : le critère strict exclut A.
  • Deux districts vulnérables : Le seuil 32 retient B et A, dans l’ordre de première apparition.
  • Un seul district : La moyenne du seul district est la moyenne globale ; elle ne peut être inférieure à 80 % d’elle-même pour ces volumes positifs.
Indice

Un district reçoit un sous-ensemble de réservoirs, pas seulement leur total.

Comprendre la correction
def districts_vulnerables(reservoirs):
    moyenne_globale = volume_moyen(reservoirs)
    groupes = reservoirs_par_district(reservoirs)
    resultat = []
    for district in liste_districts(reservoirs):
        if volume_moyen(groupes[district]) < 0.8 * moyenne_globale:
            resultat.append(district)
    return resultat
DistrictRéservoirsMoyenne (L)Sous 37600L ?
Tepua330000Oui
Fare353333,33…Non
Hiva Oro245000Non
Avera265000Non

Le seuil vaut 0.8×47000=37600L. Le résultat est ["Tepua"]. Comparer les volumes totaux serait faux, car les districts n’ont pas tous le même nombre de réservoirs. La moyenne globale est une moyenne par réservoir, et non la moyenne non pondérée des quatre moyennes de district. La calculer une seule fois évite de répéter inutilement le parcours complet.

Pourquoi ne pas comparer les totaux de district ? Tepua et Hiva Oro disposent chacun de 90000 litres, mais Tepua les répartit sur trois réservoirs et Hiva Oro sur deux : leurs moyennes valent respectivement 30000 et 45000 litres. Ils doivent donc recevoir des conclusions différentes selon le critère demandé. Cet exemple révèle immédiatement une confusion entre total et moyenne. De même, le seuil de 80% doit être calculé sur les dix réservoirs, pas sur quatre districts traités comme s’ils avaient tous le même effectif.

Ne pas confondre deux critèresUn atelier pour expérimenter

Choisissez une réponse puis confrontez votre intuition à l’explication. Vous pouvez modifier vos choix.

Lire les réponses et leurs explications
  1. Que compare districts_vulnerables ?

    Une moyenne de volume à 80% de la moyenne globale.. Le critère est relatif à la moyenne de tous les réservoirs.

  2. La moyenne globale est-elle la moyenne simple des quatre moyennes de district ?

    Pas si les effectifs diffèrent.. Il faudrait une moyenne pondérée par les effectifs.

Appuyez votre explication sur les valeurs et les conditions exactes du programme.

Voir la question dans le sujet PDF, p. 4 (nouvel onglet)
Redistribuer l’eau et recalculer le seuilUn atelier pour expérimenter

Transférez un volume de Fare versTepua, sans changer le total de la commune ni les effectifs. Observez quandTepua dépasse le seuil relatif de 37600L de moyenne. Cet atelier raisonne sur les totaux, sans simuler les canalisations.

Lire le résultat de l’expérience initiale

Districts vulnérables : Tepua.

Le transfert conserve470000L et dix réservoirs : la moyenne globale et son seuil ne changent pas.

DistrictTotal (L)RéservoirsMoyenne (L)Vulnérable ?
Tepua90000330000.00Oui
Fare160000353333.33Non
Hiva Oro90000245000.00Non
Avera130000265000.00Non

Comparer des moyennes exige de garder leurs effectifs et leur référence à l’esprit.

Revoir les notions de cet exercice

Du sujet à la méthode

Votre prochaine séance de révision

  • Séparer volume, capacité et taux de remplissage.
  • Vérifier un total regroupé en le comparant au total avant regroupement.

Retrouver ces notions dans d’autres sujets

Toutes les annales de NSI · Le guide pour préparer le bac NSI 2027

Énoncé : sujet 26_BCG_NSI_19 (PDF). Corrigé et explications pédagogiques proposés par Sofien.