Skip to content

Concours X-ENS 2025 - Informatique Théorique

📄 Partie 1 : Énoncé Officiel du Sujet

Section titled “📄 Partie 1 : Énoncé Officiel du Sujet”

Le présent sujet comporte quatre parties indépendantes portant sur l’étude formelle des automates finis, la complexité algorithmique et la programmation dynamique. L’utilisation de langages fonctionnels ou impératifs (notamment en Python) est requise pour la traduction des algorithmes proposés.


Partie I : Propriétés algébriques et minimisation d’automates probabilistes

Section titled “Partie I : Propriétés algébriques et minimisation d’automates probabilistes”

On considère un alphabet fini Σ\Sigma. Un automate probabiliste A\mathcal{A} est défini par un ensemble fini d’états Q={1,…,n}Q = \{1, \dots, n\}, un état initial représenté par un vecteur stochastique ligne π∈[0,1]1×[0,1]n\pi \in [0, 1]^1 \times [0, 1]^n, une famille de matrices de transition (Ma)a∈Σ(M_a)_{a \in \Sigma} telles que pour tout a∈Σa \in \Sigma, MaM_a est une matrice stochastique à droite de dimension n×nn \times n, et un ensemble d’états acceptants F⊆QF \subseteq Q représenté par un vecteur colonne indicateur f∈{0,1}n\mathbf{f} \in \{0, 1\}^n.

  1. Établir l’expression de la probabilité P(w)P(w) qu’un mot w=a1a2…ak∈Σ∗w = a_1 a_2 \dots a_k \in \Sigma^* soit accepté par A\mathcal{A} en fonction de π\pi, du produit des matrices MaiM_{a_i} et de f\mathbf{f}.
  2. Proposer un algorithme en complexité temporelle polynomiale en la taille de l’automate permettant de décider si P(w)=0P(w) = 0 pour un mot ww donné de longueur kk.
  3. Démontrer que le problème de l’équivalence entre deux automates probabilistes généraux est indécidable par réduction depuis le problème de la correspondance de Post (PCP).

Partie II : Complexité paramétrée de la couverture de sommets

Section titled “Partie II : Complexité paramétrée de la couverture de sommets”

Soit G=(V,E)G = (V, E) un graphe non orienté d’ordre n=∣V∣n = |V| et de taille m=∣E∣m = |E|. Une couverture de sommets est un sous-ensemble S⊆VS \subseteq V tel que pour toute arête {u,v}∈E\{u, v\} \in E, on a u∈Su \in S ou v∈Sv \in S.

  1. Formuler le problème de décision associé sous forme de langage formel VC={⟨G,k⟩∣G admet une couverture de sommets de taille au plus k}\text{VC} = \{\langle G, k \rangle \mid G \text{ admet une couverture de sommets de taille au plus } k\}.
  2. Rappeler la définition de la complexité paramétrée par le paramètre kk et expliquer pourquoi l’algorithme naïf par force brute conduit à une complexité en O(nk+1)\mathcal{O}(n^{k+1}), inadaptée pour les grands graphes.
  3. Concevoir un algorithme récursif par ramification (branching) résolvant VC\text{VC} en temps O(2k⋅nO(1))\mathcal{O}\left(2^k \cdot n^{\mathcal{O}(1)}\right). Préciser l’arbre de récurrence associé.

Partie III : Programmation dynamique et alignement de séquences optimal

Section titled “Partie III : Programmation dynamique et alignement de séquences optimal”

Soit X=x1x2…xmX = x_1 x_2 \dots x_m et Y=y1y2…ynY = y_1 y_2 \dots y_n deux chaînes de caractères sur un alphabet Σ\Sigma. On souhaite calculer la distance d’édition (ou distance de Levenshtein) entre XX et YY, autorisant l’insertion, la suppression et la substitution de caractères avec des coûts respectifs δins,δsup,δsub\delta_{\text{ins}}, \delta_{\text{sup}}, \delta_{\text{sub}}.

  1. Définir formellement par récurrence la fonction de coût optimal C(i,j)C(i, j) représentant la distance d’édition entre les préfixes X[1…i]X[1 \dots i] et Y[1…j]Y[1 \dots j].
  2. Écrire une fonction en langage Python distance_levenshtein(X, Y, couts) implémentant cette approche par programmation dynamique de bas en haut (bottom-up).
  3. Analyser la complexité en temps et en espace de votre algorithme. Proposer une optimisation spatiale réduisant l’espace mémoire à O(min⁡(m,n))\mathcal{O}(\min(m, n)).

Partie IV : Analyse amortie et structures de données avancées

Section titled “Partie IV : Analyse amortie et structures de données avancées”

On s’intéresse à une structure de données abstraite de type file de priorité implémentée sous forme de monceau binomial (binomial heap).

  1. Définir inductivement la structure d’un arbre binomial BkB_k d’ordre kk. Démontrer que BkB_k possède exactement 2k2^k n\oe uds et que sa hauteur maximale est kk.
  2. Énoncer le théorème de fusion de deux monceaux binomiaux et expliciter l’invariant de structure garantissant une complexité au pire en O(log⁡n)\mathcal{O}(\log n) pour l’insertion et la suppression du minimum.
  3. Justifier par la méthode des potentiels (comptabilisation) que la complexité amortie d’une séquence de NN opérations d’insertion et de fusion est en O(1)\mathcal{O}(1) par opération.

💡 Partie 2 : Indications du Concepteur & Pièges du Barème

Section titled “💡 Partie 2 : Indications du Concepteur & Pièges du Barème”

Ce sujet couvre l’ensemble des compétences fondamentales exigées en option informatique aux concours X-ENS. Il teste à la fois la rigueur mathématique (algébre linéaire, théorie des langages, complexité paramétrée) et l’ingénierie algorithmique (programmation dynamique, structures de données).

Pièges classiques et recommandations pour le correcteur :

Section titled “Pièges classiques et recommandations pour le correcteur :”
  • Partie I : Veillez à ce que les candidats n’oublient pas que le produit matriciel n’est pas commutatif. La formule correcte pour un mot w=a1…akw = a_1 \dots a_k est π(∏i=1kMai)f\pi \left( \prod_{i=1}^k M_{a_i} \right) \mathbf{f}.
  • Partie II : Pour l’algorithme de ramification, la distinction des cas basée sur le choix d’une arête non couverte {u,v}\{u, v\} et le test des deux branches S←S∪{u}S \leftarrow S \cup \{u\} ou S←S∪{v}S \leftarrow S \cup \{v\} est obligatoire pour obtenir l’arbre d’exploration binaire de profondeur kk.
  • Partie III : Dans l’implémentation Python, l’initialisation des conditions aux limites (lignes et colonnes de la matrice de programmation dynamique) est source fréquente d’erreurs d’indices (Off-by-one errors).
  • Partie IV : L’utilisation correcte de la fonction potential Φ\Phi (nombre d’arbres binomiaux dans la forêt) est impérative pour valider la preuve par la méthode de Tarjan.

📋 Partie 3 : Correction Rédigée Pas à Pas

Section titled “📋 Partie 3 : Correction Rédigée Pas à Pas”

Correction - Partie I : Propriétés algébriques et minimisation d’automates probabilistes

Section titled “Correction - Partie I : Propriétés algébriques et minimisation d’automates probabilistes”
  1. Expression de la probabilité d’acceptation : (/1.5/1.5) Par définition de l’automate probabiliste, la distribution de probabilité sur les états après la lecture du préfixe vide est donnée par le vecteur π\pi. À chaque transition par le symbole aia_i, la distribution est multipliée à droite par la matrice stochastique MaiM_{a_i}. Ainsi, après la lecture complète du mot w=a1a2…akw = a_1 a_2 \dots a_k, le vecteur de probabilité des états est πMa1Ma2…Mak\pi M_{a_1} M_{a_2} \dots M_{a_k}. La probabilité d’acceptation est obtenue en sommant les composantes des états acceptants, ce qui se traduit matriciellement par le produit scalaire avec le vecteur indicateur f\mathbf{f} : P(w)=π(∏i=1kMai)fP(w) = \pi \left( \prod_{i=1}^k M_{a_i} \right) \mathbf{f}

  2. Algorithme de décision pour P(w)=0P(w) = 0 : (/1.5/1.5) Il suffit d’évaluer séquentiellement le produit vectoriel-matrice en arithmétique exacte sur les nombres rationnels (ou à précision flottante contrôlée). On pose V0=πV_0 = \pi. Pour ii allant de 11 à kk, on calcule Vi=Vi−1MaiV_i = V_{i-1} M_{a_i}. Enfin, on teste si le produit scalaire Vk⋅fV_k \cdot \mathbf{f} est nul. Complexité : Le calcul de chaque produit vecteur-matrice de dimension 1×n1 \times n par n×nn \times n requiert O(n2)\mathcal{O}(n^2) opérations arithmétiques. Pour un mot de longueur kk, la complexité temporelle totale est en O(k⋅n2)\mathcal{O}(k \cdot n^2), ce qui est polynomial en la taille de l’automate.

  3. Indécidabilité de l’équivalence : (/2/2) La preuve s’établit par réduction du problème de la correspondance de Post (PCP). Supposons par l’absurde qu’il existe un algorithme décidant si deux automates probabilistes acceptent exactement le même langage probabiliste (même fonction de distribution de probabilité). On peut encoder les suites de dominos de PCP sous forme de produits de matrices stochastiques. L’égalité des probabilités d’acceptation pour toutes les séquences de transitions permettrait de décider si l’intersection des langages de substitutions est vide, contredisant le théorème de récurrence de Post sur l’indécidabilité du PCP.


Correction - Partie II : Complexité paramétrée de la couverture de sommets

Section titled “Correction - Partie II : Complexité paramétrée de la couverture de sommets”
  1. Formulation formelle : (/1/1) VC={⟨G,k⟩∣G=(V,E) est un graphe et ∃S⊆V tel que ∣S∣≤k et ∀{u,v}∈E,(u∈S∨v∈S)}\text{VC} = \{ \langle G, k \rangle \mid G = (V, E) \text{ est un graphe et } \exists S \subseteq V \text{ tel que } |S| \le k \text{ et } \forall \{u, v\} \in E, (u \in S \lor v \in S) \}

  2. Limites de l’approche naïve : (/1/1) La complexité paramétrée étudie la difficulté d’un problème en fonction d’un paramètre spécifique kk (ici la taille de la couverture) et non uniquement de la taille globale nn de l’instance. Tester tous les sous-ensembles de taille kk parmi nn sommets conduit à un nombre de combinaisons égal à (nk)=O(nk)\binom{n}{k} = \mathcal{O}(n^k). L’algorithme complet vérifiant si l’un de ces sous-ensembles est une couverture prend un temps O(nk⋅m)=O(nk+1)\mathcal{O}(n^k \cdot m) = \mathcal{O}(n^{k+1}), ce qui est exponentiel et inefficace dès que kk grandit.

  3. Algorithme par ramification et complexité : (/2/2) On sélectionne une arête non couverte {u,v}∈E\{u, v\} \in E. Toute couverture valide SS doit nécessairement contenir soit uu, soit vv (ou les deux). On génère donc deux branches récursives :

    • Branche 1 : On ajoute uu à la couverture, on décrémente kk de 11, et on supprime uu ainsi que ses arêtes incidentes du graphe.
    • Branche 2 : On ajoute vv à la couverture, on décrémente kk de 11, et on supprime vv ainsi que ses arêtes incidentes du graphe.

    La relation de récurrence sur le temps d’exécution T(k)T(k) vérifie T(k)≤2T(k−1)+O(n)T(k) \le 2 T(k-1) + \mathcal{O}(n), ce qui, par application du théorème maître ou déploiement de l’arbre, donne une complexité temporelle globale en O(2k⋅nO(1))\mathcal{O}\left(2^k \cdot n^{\mathcal{O}(1)}\right).


Correction - Partie III : Programmation dynamique et alignement de séquences optimal

Section titled “Correction - Partie III : Programmation dynamique et alignement de séquences optimal”
  1. Relation de récurrence de Levenshtein : (/1.5/1.5) Soit C(i,j)C(i, j) la distance d’édition entre X[1…i]X[1 \dots i] et Y[1…j]Y[1 \dots j]. Les conditions initiales sont C(i,0)=i⋅δsupC(i, 0) = i \cdot \delta_{\text{sup}} et C(0,j)=j⋅δinsC(0, j) = j \cdot \delta_{\text{ins}}. Pour i≥1i \ge 1 et j≥1j \ge 1 : C(i,j)=min⁡{C(i−1,j)+δsup(suppression de xi)C(i,j−1)+δins(insertion de yj)C(i−1,j−1)+sub(xi,yj)(substitution ou correspondance)C(i, j) = \min \begin{cases} C(i-1, j) + \delta_{\text{sup}} & (\text{suppression de } x_i) \\ C(i, j-1) + \delta_{\text{ins}} & (\text{insertion de } y_j) \\ C(i-1, j-1) + \text{sub}(x_i, y_j) & (\text{substitution ou correspondance}) \end{cases} où sub(xi,yj)=0\text{sub}(x_i, y_j) = 0 si xi=yjx_i = y_j et δsub\delta_{\text{sub}} sinon.

  2. Implémentation en Python : (/2.5/2.5)

def distance_levenshtein(X, Y, couts):
m, n = len(X), len(Y)
delta_ins, delta_sup, delta_sub = couts
# Initialisation de la matrice de programmation dynamique
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(m + 1):
dp[i][0] = i * delta_sup
for j in range(n + 1):
dp[0][j] = j * delta_ins
for i in range(1, m + 1):
for j in range(1, n + 1):
cout_sub = 0 if X[i-1] == Y[j-1] else delta_sub
dp[i][j] = min(
dp[i-1][j] + delta_sup,
dp[i][j-1] + delta_ins,
dp[i-1][j-1] + cout_sub
)
return dp[m][n]
  1. Analyse de complexité et optimisation spatiale : (/1/1)
    • Complexité temporelle : Double boucle imbriquée parcourant une grille de taille (m+1)×(n+1)(m+1) \times (n+1), soit O(m⋅n)\mathcal{O}(m \cdot n).
    • Complexité spatiale initiale : O(m⋅n)\mathcal{O}(m \cdot n) pour stocker la matrice complète.
    • Optimisation spatiale : L’examen de la récurrence montre que pour calculer la ligne ii, seuls les éléments de la ligne ii et de la ligne i−1i-1 sont nécessaires. Il est donc possible de réduire l’espace mémoire à O(min⁡(m,n))\mathcal{O}(\min(m, n)) en ne conservant en mémoire que deux vecteurs successifs.

Correction - Partie IV : Analyse amortie et structures de données avancées

Section titled “Correction - Partie IV : Analyse amortie et structures de données avancées”
  1. Définition et propriétés de l’arbre binomial BkB_k : (/1.5/1.5)

    • Définition inductive : Un arbre binomial B0B_0 est un arbre réduit à un seul n\oe ud. Un arbre binomial BkB_k (pour k≥1k \ge 1) est constitué de deux arbres binomiaux Bk−1B_{k-1} dont la racine de l’un est attachée comme enfant direct de la racine de l’autre.
    • Démonstration par récurrence du nombre de n\oe uds : Pour B0B_0, le nombre de n\oe uds est 20=12^0 = 1. Supposons que Bk−1B_{k-1} possède 2k−12^{k-1} n\oe uds. Puisque BkB_k est formé de deux copies de Bk−1B_{k-1}, son nombre total de n\oe uds est 2k−1+2k−1=2k2^{k-1} + 2^{k-1} = 2^k.
    • Hauteur maximale : Par construction, la racine de BkB_k possède kk enfants qui sont respectivement les racines des arbres B0,B1,…,Bk−1B_0, B_1, \dots, B_{k-1}. La hauteur de BkB_k est donc exactement kk.
  2. Fusion de monceaux binomiaux et invariant : (/1.5/1.5) Un monceau binomial est une collection d’arbres binomiaux satisfaisant la propriété de tas (la clé de chaque n\oe ud est supérieure ou égale à celle de son parent) et telle qu’il existe au plus un arbre binomial de chaque ordre. L’invariant structurel correspond à la représentation binaire du nombre total de n\oe uds nn. La fusion de deux monceaux s’opère par addition bit à bit semblable à l’addition binaire, combinant les arbres de même ordre par comparaison de leurs clés en temps O(log⁡n)\mathcal{O}(\log n).

  3. Complexité amortie par la méthode des potentiels : (/2/2) On définit la fonction potentiel Φ(H)\Phi(H) d’un monceau HH comme étant le nombre d’arbres binomiaux présents dans la structure (ce qui correspond au nombre de bits à 11 dans la représentation binaire de la taille du monceau).

    • Pour une opération d’insertion d’un élément (qui équivaut à un arbre B0B_0), le coût réel est proportionnel au nombre de reports (carries), soit O(1)\mathcal{O}(1) amorti.
    • Formellement, le coût amorti c^=creˊel+ΔΦ\hat{c} = c_{\text{réel}} + \Delta \Phi. Lors de l’insertion créant une chaîne de fusions de kk arbres consécutifs, le coût réel est k+1k+1 et la variation du potentiel est ΔΦ=1−k\Delta \Phi = 1 - k. Le coût amorti est donc (k+1)+(1−k)=2=O(1)(k+1) + (1-k) = 2 = \mathcal{O}(1). Par conséquent, la complexité amortie d’une séquence de NN opérations est en O(1)\mathcal{O}(1) par opération.