Adloun

Corrigé X-ENS 2025 Informatique B MP-PC-PSI — Partie IV (Q10 à Q15) : Programmation dynamique avec cases bonus

Sujet officiel du concours X-ENS, session 2025, épreuve Informatique B MP-PC-PSI. Corrigé rédigé par Ibrahim Alame.

Sujet officiel (PDF, site du concours)

Énoncé

Grille T de taille , sauts par défaut sauts (ensemble ), dictionnaire bonus ; tous les sauts vérifient (*) : ou ( et ). On remplit poids_opt[i][j][c], poids d'un chemin optimal de à lorsque l'ensemble des cases bonus déjà activées a pour code , et saut_opt[i][j][c], un saut optimal à jouer depuis .

Les cases bonus sont numérotées de à ; est l'ensemble des sauts activés par la case numéro . Un masque de booléens indique les cases activées ; son code est l'entier qui s'écrit en base 2 (, ). Ainsi [False, False] a pour code 0 et [True, False] a pour code 1. Depuis une case non bonus, on utilise et les activés, le code étant inchangé. Depuis la case bonus numéro , on ajoute et les successeurs sont pris avec mis à True. Les masques doivent être traités par inclusion décroissante. L'algorithme suggéré part du masque plein et engendre, à l'aide d'une file, chaque ligne suivante en basculant un True en False, jusqu'au masque vide.

Fonctions supposées données : ranger_bonus(bonus) renvoie (bonus_au_rang, rang_du_bonus), où bonus_au_rang[k] est la liste des sauts de la case numéro et rang_du_bonus[(i,j)] le numéro de la case ; ajouter_bonus(bonus, rang_du_bonus, i, j, bonus_actifs, code_bonus_actifs) renvoie le code après activation de , inchangé si ce n'est pas une case bonus.

Q10. Écrire code_bonus(masque_bonus).
Q11. Écrire la définition de poids_opt[i][j][], à l'aide de et des .
Q12. Écrire combinaisons_bonus(nb_bonus), qui renvoie la liste des masques par inclusion décroissante, selon l'algorithme décrit.
Q13. Écrire la fonction trouver_sauts_possibles, d'arguments sauts, bonus_au_rang et masque_bonus, qui renvoie la liste des sauts possibles.
Q14. Compléter les sept trous du code suivant, puis donner sa complexité.


def trouve_dynamique(T, sauts, bonus):
  N = len(T)
  nb_bonus = len(bonus)
  nb_code_bonus = ...                             # A COMPLETER (1)
  poids_opt = [[[INFINI for bonus_code in range(nb_code_bonus)]
                        for j in range(N)] for i in range(N)]
  saut_opt = [[[(0,0,0) for bonus_code in range(nb_code_bonus)]
                        for j in range(N)] for i in range(N)]
  (bonus_au_rang, rang_du_bonus) = ranger_bonus(bonus)
  for bonus_actifs in combinaisons_bonus(nb_bonus):
    code_bonus_actifs = code_bonus(bonus_actifs)
    poids_opt[N-1][N-1][code_bonus_actifs] = ...  # A COMPLETER (2)
    sauts_possibles = ...                         # A COMPLETER (3)
    for i in range(...):                          # A COMPLETER (4)
      for j in range(...):                        # A COMPLETER (5)
        code_bonus_dest = ajouter_bonus(bonus, rang_du_bonus, i, j,
                                        bonus_actifs, code_bonus_actifs)
        if (i,j) in bonus:
          sauts_possibles_final = sauts_possibles + bonus[(i,j)]
        else:
          sauts_possibles_final = sauts_possibles
        for (delta_i, delta_j) in sauts_possibles_final:
          i_dest = i+delta_i
          j_dest = j+delta_j
          if (i_dest in range(N) and j_dest in range(N)):
            poids_opt_dest = poids_opt[i_dest][j_dest][code_bonus_dest]
            if (poids_opt[i][j][code_bonus_actifs] > poids_opt_dest):
              poids_opt[i][j][code_bonus_actifs] = ... # A COMPLETER (6)
              saut_opt[i][j][code_bonus_actifs] = ...  # A COMPLETER (7)
        poids_opt[i][j][code_bonus_actifs] += T[i][j]
  return (poids_opt, saut_opt)

Q15. Écrire solution_dynamique(saut_opt, N), qui renvoie le chemin optimal (liste de cases), ou [] s'il n'existe aucun chemin du départ à l'arrivée.

Corrigé

Q10. Le code vaut . On l'évalue par la méthode de Horner, en lisant le masque de la fin vers le début (bit de poids fort d'abord).


def code_bonus(masque_bonus):
    code = 0
    for k in range(len(masque_bonus) - 1, -1, -1):   # de b_(n-1) à b_0
        code = 2 * code              # décalage d'un rang en base 2
        if masque_bonus[k]:
            code = code + 1          # le bit b_k vaut 1
    return code

Invariant : après le traitement de l'indice , ; pour , c'est le code cherché. Coût . Vérifié : [False, False] , [True, False] , [False, True] , [True, True, True] , [] . Ce que le correcteur attend : le jury relève deux erreurs, compter les True au lieu de calculer l'entier, et calculer en base 10.

Q11. Notons pour poids_opt[i][j][] et posons, pour la case et le masque ,

et le masque où est mis à True si est la case bonus numéro , sinon. Alors :

et, pour ,

avec la convention (INFINI) quand aucun successeur n'est dans la grille.

Justification (sous-structure optimale). Un chemin correct de à l'arrivée, avec les bonus de activés, est soit réduit à l'arrivée, soit formé d'un premier saut de qui reste dans la grille, puis d'un chemin correct depuis la case atteinte avec les bonus de . Son poids est plus celui de ce reste. Ce reste doit être optimal : sinon, en le remplaçant par un meilleur, on améliorerait le tout (argument de couper-coller). Réciproquement, toute telle concaténation est un chemin correct. Le cas de l'arrivée est à part : le chemin s'y arrête, et d'ailleurs, par (), aucun saut n'en part en restant dans la grille. Ce que le correcteur attend :* le jury signale qu'il manquait souvent le test de validité de la case successeur.

100 % gratuit

La suite du corrigé est sur Adloun

Le corrigé rédigé en entier, question par question, et le tuteur pour poser des questions sur ce sujet.

Voir le corrigé complet, gratuitement

Inscription gratuite en 30 secondes (e-mail, nom d'utilisateur, mot de passe, classe ou profil), sans carte bancaire : arrivée directe sur le corrigé.

Toutes les parties de l'épreuve

Corrigé complet gratuit →