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éservoir | Capacité (L) | Volume (L) | District |
|---|---|---|---|
| Nuiavai | 100000 | 55000 | Tepua |
| Farepape | 120000 | 45000 | Fare |
| Vaipuna | 80000 | 60000 | Hiva Oro |
| Vaihere | 95000 | 20000 | Fare |
| Teanavai | 110000 | 90000 | Avera |
| Matavai | 70000 | 25000 | Tepua |
| Anaʻitea | 85000 | 30000 | Hiva Oro |
| Faaroa | 60000 | 40000 | Avera |
| Vaitiare | 105000 | 95000 | Fare |
| Motuavai | 90000 | 10000 | Tepua |
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')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| District | Volume total (L) |
|---|---|
| Tepua | 90000 |
| Fare | 160000 |
| Hiva Oro | 90000 |
| Avera | 130000 |
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.
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.
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| District | Réservoirs | Moyenne (L) | Sous 37600L ? |
|---|---|---|---|
| Tepua | 3 | 30000 | Oui |
| Fare | 3 | 53333,33… | Non |
| Hiva Oro | 2 | 45000 | Non |
| Avera | 2 | 65000 | Non |
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
- 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.
- 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.
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.
| District | Total (L) | Réservoirs | Moyenne (L) | Vulnérable ? |
|---|---|---|---|---|
| Tepua | 90000 | 3 | 30000.00 | Oui |
| Fare | 160000 | 3 | 53333.33 | Non |
| Hiva Oro | 90000 | 2 | 45000.00 | Non |
| Avera | 130000 | 2 | 65000.00 | Non |
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.
