Solution de Zoom d'un dessin en pixels - Sujet 44 - EP NSI 2025
Énoncé du problème
Exercice 1
EXERCICE 1 (10 points)
Dans cet exercice on cherche à calculer la moyenne pondérée d’un élève dans une matière donnée. Chaque note est associée à un coefficient qui la pondère.
Par exemple, si ses notes sont : 14 avec coefficient 3, 12 avec coefficient 1 et 16 avec coefficient 2, sa moyenne pondérée sera donnée par
$$\frac{14 \times 3 + 12 \times 1 + 16 \times 2}{3 + 1 + 2} = 14,333…$$
Écrire une fonction moyenne :
- qui prend en paramètre une liste
notesnon vide de tuples à deux éléments entiers de la forme(note, coefficient)(intoufloat) positifs ou nuls ; - et qui renvoie la moyenne pondérée des notes de la liste sous forme de flottant si la somme des coefficients est non nulle, None sinon.
Exemple :
>>> moyenne([(8, 2), (12, 0), (13.5, 1), (5, 0.5)])
9.142857142857142
>>> moyenne([(3, 0), (5, 0)])
None
Exercice 2
EXERCICE 2 (10 points)
[Figure : dessin en pixels noirs et blancs représentant un cœur, tracé sur une grille quadrillée.]
On travaille sur des dessins en noir et blanc obtenus à partir de pixels noirs et blancs : La figure « cœur » ci-dessus va servir d’exemple. On la représente par une grille de nombres, c’est-à-dire par une liste composée de sous-listes de même longueur. Chaque sous-liste représentera donc une ligne du dessin.
Dans le code ci-dessous, la fonction affiche permet d’afficher le dessin. Les pixels noirs (1 dans la grille) seront représentés par le caractère '*' et les pixels blancs (0 dans la grille) par une espace.
La fonction liste_zoom prend en argument une liste liste_depart et un entier k. Elle renvoie une liste où chaque élément de liste_depart est dupliqué k fois.
La fonction dessin_zoom prend en argument une grille grille et renvoie une nouvelle grille où toutes les lignes de grille sont zoomées k fois et répétées k fois.
Compléter les fonctions liste_zoom et dessin_zoom du code suivant :
def affiche(dessin):
''' affichage d'une grille : les 1 sont représentés par
un "*" , les 0 par une espace " " '''
for ligne in dessin:
affichage = ''
for col in ligne:
if col == 1:
affichage = affichage + "*"
else:
affichage = affichage + " "
print(affichage)
def liste_zoom(liste_depart,k):
'''renvoie une liste contenant k fois chaque élément de
liste_depart'''
liste_zoomee = ...
for elt in ... :
for i in range(k):
...
return liste_zoomee
def dessin_zoom(grille,k):
'''renvoie une grille où les lignes sont zoomées k fois
ET répétées k fois'''
grille_zoomee=[]
for ligne in grille:
ligne_zoomee = ...
for i in range(k):
... .append(...)
return grille_zoomee
Exemples :
>>> coeur = [[0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0],
[0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0],
[0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]]
>>> affiche(coeur)
** **
* * * *
* * *
* *
* *
* *
* *
* *
* *
*
>>> affiche(dessin_zoom(coeur,2))
**** ****
**** ****
** ** ** **
** ** ** **
** ** **
** ** **
** **
** **
** **
** **
** **
** **
** **
** **
** **
** **
** **
** **
**
**
>>> liste_zoom([1,2,3],3)
[1, 1, 1, 2, 2, 2, 3, 3, 3]
Les contraintes ci-dessous sont ajoutées par la plateforme et ne font pas partie du sujet.
Exercice 1
Contraintes :
1 <= len(notes) <= 10^4(la listenotesest non vide)- chaque élément de
notesest un tuple(note, coefficient)à deux éléments noteetcoefficientsont chacun unintou unfloat, avec0 <= note <= 10^3et0 <= coefficient <= 10^3moyennerenvoie unfloatsi la somme des coefficients est non nulle, etNonesi cette somme est nulle
Exercice 2
Contraintes :
1 <= k <= 10grilleest une liste de1 <= nombre de lignes <= 100sous-listes, toutes de même longueur1 <= nombre de colonnes <= 100- chaque pixel de
grillevaut0ou1 - pour
liste_zoom:0 <= len(liste_depart) <= 10^4 dessin_zoomrenvoie une nouvelle grille et ne modifie pasgrille
Solution
Solution - Sujet 44
Exercice 1 - la moyenne pondérée
L’idée. Une moyenne pondérée, c’est la somme de toutes les notes multipliées par leur coefficient, divisée par la somme des coefficients. Il suffit donc de parcourir la liste une seule fois en gardant deux totaux : un total pondéré (on y ajoute note * coefficient) et un total des coefficients (on y ajoute coefficient). À la fin, on divise le premier par le second. Seul piège : si la somme des coefficients vaut 0, la division est impossible, et le sujet demande alors de renvoyer None.
Un petit exemple. Pour [(8, 2), (12, 0), (13.5, 1), (5, 0.5)], le total pondéré vaut 8*2 + 12*0 + 13.5*1 + 5*0.5 = 32.0 et le total des coefficients vaut 2 + 0 + 1 + 0.5 = 3.5. La moyenne est donc 32.0 / 3.5, soit 9.142857142857142.
def moyenne(notes):
total_pondere = 0
total_coefficients = 0
for note, coefficient in notes:
total_pondere = total_pondere + note * coefficient
total_coefficients = total_coefficients + coefficient
# Sans coefficient, il n'y a pas de moyenne : on ne peut pas diviser par 0
if total_coefficients == 0:
return None
return total_pondere / total_coefficients
total_pondere accumule les produits note * coefficient, total_coefficients accumule les coefficients. L’écriture for note, coefficient in notes sépare directement chaque tuple en ses deux valeurs, ce qui évite d’écrire element[0] et element[1]. Le test sur total_coefficients se fait après la boucle, une seule fois : c’est seulement à ce moment-là que l’on connaît la somme complète. Enfin, l’opérateur / renvoie toujours un flottant, même quand les deux totaux sont des entiers : le résultat est donc bien du type demandé.
Exercice 2 - le zoom d’un dessin
L’idée pour liste_zoom. On veut recopier chaque élément k fois de suite. On part d’une liste vide, on parcourt les éléments de liste_depart un par un, et pour chaque élément on fait k tours de boucle en l’ajoutant à chaque tour. C’est exactement la double boucle dessinée dans le squelette du sujet.
Pour [1, 2, 3] et k = 3 : on ajoute trois fois 1, puis trois fois 2, puis trois fois 3, ce qui donne [1, 1, 1, 2, 2, 2, 3, 3, 3].
L’idée pour dessin_zoom. Agrandir un dessin, c’est l’agrandir dans les deux directions. En largeur : chaque ligne doit voir ses pixels dupliqués k fois, et cela, liste_zoom sait déjà le faire. En hauteur : cette ligne agrandie doit être ajoutée k fois de suite à la nouvelle grille. Pour chaque ligne de départ, on calcule donc sa version zoomée, puis on l’ajoute k fois.
def liste_zoom(liste_depart,k):
'''renvoie une liste contenant k fois chaque élément de
liste_depart'''
liste_zoomee = []
for elt in liste_depart:
for i in range(k):
liste_zoomee.append(elt)
return liste_zoomee
def dessin_zoom(grille,k):
'''renvoie une grille où les lignes sont zoomées k fois
ET répétées k fois'''
grille_zoomee=[]
for ligne in grille:
ligne_zoomee = liste_zoom(ligne,k)
for i in range(k):
# une copie à chaque tour : les k lignes doivent rester indépendantes
grille_zoomee.append(list(ligne_zoomee))
return grille_zoomee
Dans liste_zoom, la boucle intérieure for i in range(k) ne sert qu’à compter jusqu’à k : la variable i n’est pas utilisée, seul le nombre de tours compte. Dans dessin_zoom, ligne_zoomee est la ligne courante déjà élargie ; on l’ajoute k fois pour l’épaissir. On ajoute list(ligne_zoomee), c’est-à-dire une copie, et non k fois la même liste : sinon les k lignes ajoutées seraient un seul et même objet en mémoire. Enfin, ni grille ni ses sous-listes ne sont modifiées : tout est écrit dans grille_zoomee, qui est bien une nouvelle grille.