Solution de Zoom d'un dessin en pixels - Sujet 44 - EP NSI 2025

Moyen Officiel
Python (3.14.0)

É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 notes non vide de tuples à deux éléments entiers de la forme (note, coefficient) (int ou float) 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 liste notes est non vide)
  • chaque élément de notes est un tuple (note, coefficient) à deux éléments
  • note et coefficient sont chacun un int ou un float, avec 0 <= note <= 10^3 et 0 <= coefficient <= 10^3
  • moyenne renvoie un float si la somme des coefficients est non nulle, et None si cette somme est nulle

Exercice 2

Contraintes :

  • 1 <= k <= 10
  • grille est une liste de 1 <= nombre de lignes <= 100 sous-listes, toutes de même longueur 1 <= nombre de colonnes <= 100
  • chaque pixel de grille vaut 0 ou 1
  • pour liste_zoom : 0 <= len(liste_depart) <= 10^4
  • dessin_zoom renvoie une nouvelle grille et ne modifie pas grille

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.