Aller au contenu principal

Algorithmiques élémentaires & pensée computationnelle · L1 · Section 6/6

Annales corrigées

Progression

Points d’expérience : XPSérie de jours consécutifs : · —Progression du module : — / —compris

#Annales corrigées

Cette page rassemble des exercices issus de la première UE d'informatique du semestre 1, l'UE SPUF100 « Bases de l'informatique 1 » de la Licence Informatique d'Université Côte d'Azur (campus Valrose). Le cours « Outils formels pour l'informatique » est assuré par Enrico Formenti ; les feuilles de TD couvrent les ensembles et le dénombrement, les relations et les ordres, l'induction, les récurrences, la logique et les langages formels.

Source exacte. Les énoncés reproduits ici proviennent des feuilles de travaux dirigés distribuées entre 2020 et 2023 — TD 3 « Induction », TD 4 « Dénombrement », TD 5 « Récurrence » — et des transparents de cours correspondants. La sélection privilégie les exercices qui portent sur les fondements de la pensée computationnelle : prouver qu'un algorithme termine et fait ce qu'il prétend, compter les cas d'un problème avant de l'énumérer, et résoudre l'équation de récurrence qui décrit le coût d'un algorithme récursif.

FeuilleThèmeExercices repris ici
TD 3Induction1, 4, 5, 6
TD 4Dénombrement3, 7, 8, 9
TD 5Récurrence1, 2, 3, 6, 7

Les transparents de cours fournissent en complément le matériel de référence utilisé dans les corrections et dans la page complexité : la table du temps d'exécution en fonction de 2n2^{n} et le voyageur de commerce (cours 4, dénombrement), la formule de Stirling (cours 4), l'équation de partition et la recherche dichotomique ainsi que les tours de Hanoï (cours 5, suites récurrentes), l'équation caractéristique d'ordre 2 (cours 5).

Comment travailler cette page. Les corrections sont rédigées comme on attend de les lire sur une copie : hypothèses explicites, cas de base vérifiés, hérédité justifiée, conclusion énoncée. Cherchez avant d'ouvrir.

#Exercice 1 — Des pièces de monnaie à tout faire

Énoncé (TD 3, exercice 1). Nous voulons justifier l'introduction d'une nouvelle pièce de monnaie de 3 centimes d'euro. Pour cela, montrez que pour tout objet ayant un prix supérieur ou égal à 8 centimes, il est possible de le payer avec des pièces de 3 et 5 centimes uniquement.

Correction détaillée

Reformulation. Il s'agit de montrer que tout entier n8n \ge 8 s'écrit n=3a+5bn = 3a + 5b avec a,bNa, b \in \mathbb{N}.

Pourquoi trois cas de base. L'hérédité naturelle consiste à dire : si n3n - 3 est payable, alors nn l'est, en ajoutant une pièce de 3. Mais cette hérédité ne couvre que les n11n \ge 11, puisqu'elle exige n38n - 3 \ge 8. Il faut donc amorcer trois valeurs consécutives, de façon que tout entier plus grand retombe sur l'une d'elles :

8=3+5,9=3+3+3,10=5+5.8 = 3 + 5, \qquad 9 = 3 + 3 + 3, \qquad 10 = 5 + 5.

Hérédité. Soit n11n \ge 11 et supposons la propriété vraie pour n3n - 3. Comme 8n3<n8 \le n - 3 < n, l'hypothèse de récurrence s'applique : n3=3a+5bn - 3 = 3a + 5b. Alors

n=3a+5b+3=3(a+1)+5b,n = 3a + 5b + 3 = 3(a + 1) + 5b,

qui est bien une combinaison de pièces de 3 et 5. Par récurrence généralisée sur nn, la propriété est vraie pour tout n8n \ge 8. \blacksquare

La leçon sur le pas d'induction. L'erreur classique est de n'amorcer qu'un seul cas de base (8=3+58 = 3 + 5) et de conclure pour tout n8n \ge 8 : le raisonnement ne couvre alors que 8,11,14,8, 11, 14, \dots et laisse 9,10,12,9, 10, 12, \dots sans preuve. La règle générale : si l'hérédité fait appel à nkn - k, il faut kk cas de base consécutifs. Ici k=3k = 3, donc trois cas de base.

Vérification numérique. 8=3+58 = 3+5, 9=3+3+39 = 3+3+3, 10=5+510 = 5+5, 11=3+3+511 = 3+3+5, 12=3+3+3+312 = 3+3+3+3, 13=3+5+513 = 3+5+5, 14=3+3+3+514 = 3+3+3+5. Les valeurs 11 à 77 (sauf 33 et 55) ne sont effectivement pas payables : le seuil de 8 est optimal.

#Exercice 2 — Attention aux conclusions trop rapides

Énoncé (TD 3, exercice 4). Considérons l'induction généralisée suivante sur l'ensemble des points du plan 2D. Soit P(n)P(n) la propriété : « nn points distincts du plan 2D sont alignés ».

  1. Vérifiez que P(2)P(2) est vraie.
  2. Supposez que P(n)P(n) soit vraie et considérez n+1n+1 points p1,p2,,pn,pn+1p_1, p_2, \dots, p_n, p_{n+1}. Comme P(n)P(n) est vraie, le sous-ensemble p1,p2,,pnp_1, p_2, \dots, p_n est aligné sur une droite d1d_1 et, de même, le sous-ensemble p2,,pn+1p_2, \dots, p_{n+1} est sur une droite d2d_2. Comme d1d_1 et d2d_2 ont nn points en commun (avec n2n \ge 2), alors d1=d2d_1 = d_2.
  3. Peut-on donc conclure que nN\forall n \in \mathbb{N}, P(n)P(n) est vraie ?
Correction détaillée

1. P(2)P(2) est vraie : deux points distincts du plan déterminent toujours une droite, donc ils sont alignés. Le cas de base est donc correct.

2. Le pas d'induction est faux en tant qu'énoncé général. Comptons les points communs à d1d_1 et d2d_2. La droite d1d_1 passe par p1,,pnp_1, \dots, p_n, la droite d2d_2 par p2,,pn+1p_2, \dots, p_{n+1}. Les points communs aux deux ensembles sont p2,,pnp_2, \dots, p_n, c'est-à-dire n1n - 1 points, et non nn comme l'affirme l'énoncé.

Cette correction d'un point change tout. Deux droites distinctes ont au plus un point commun. Donc pour conclure d1=d2d_1 = d_2, il faut que n12n - 1 \ge 2, c'est-à-dire n3n \ge 3. L'implication P(n)P(n+1)P(n) \Rightarrow P(n+1) n'est donc démontrée que pour n3n \ge 3 ; elle est sans fondement pour n=2n = 2.

3. Non, on ne peut pas conclure. L'induction exige que le cas de base soit assez « bas » pour que l'hérédité s'y accroche. Ici l'hérédité démarre à n=3n = 3 : il faudrait donc disposer de P(3)P(3) comme cas de base. Or P(3)P(3) est fausse : trois points non alignés du plan le contredisent (par exemple (0,0)(0,0), (1,0)(1,0), (0,1)(0,1)). L'induction ne peut pas démarrer, et la conclusion nP(n)\forall n\, P(n) tombe.

La leçon. Une induction ne vaut que par la jonction du cas de base et de l'hérédité : il ne suffit pas que chacune des deux étapes soit vraie séparément, il faut qu'elles s'enchaînent sans trou. Le symptôme à surveiller est exactement celui-ci : une hérédité prouvée sous une condition sur nn (n3n \ge 3) et un cas de base plus petit (n=2n = 2). C'est le même défaut que dans le sophisme « tous les chevaux ont la même couleur ».

#Exercice 3 — Correction de l'algorithme d'Euclide

Énoncé (TD 3, exercice 5). Prouver que l'algorithme du listing ci-dessous est correct, c'est-à-dire que pour chaque paire d'entiers a,ba, b il renvoie bien le PGCD de aa et bb. Suggestion : il convient de faire une induction généralisée sur a+ba + b.

texttext

1function PGCD(a, b: integer)2begin3  if (b > a) then return PGCD(b, a);4  if (b == 0) then return a;5  else return PGCD(a - b, b);6end
Correction détaillée

Ce qu'il faut prouver. La propriété P(a,b)P(a,b) : « l'appel PGCD(a,b) termine et renvoie gcd(a,b)\gcd(a,b) », pour tous entiers a,b0a, b \ge 0 non tous deux nuls.

Les deux faits arithmétiques. On utilise les deux identités classiques, valables pour ab0a \ge b \ge 0 :

gcd(a,0)=a,gcd(a,b)=gcd(ab,b).\gcd(a, 0) = a, \qquad \gcd(a, b) = \gcd(a - b, b).

La seconde exprime que l'ensemble des diviseurs communs de aa et bb est exactement celui de aba-b et bb : tout dd divisant aa et bb divise aba - b ; réciproquement tout dd divisant aba-b et bb divise (ab)+b=a(a-b)+b = a. Les deux entiers ont donc le même PGCD.

Terminaison. Le point délicat est la première ligne : l'appel PGCD(b, a) conserve la somme a+ba + b. Une induction simple sur a+ba+b ne suffit donc pas, puisque la mesure ne décroît pas sur ce cas. On prend une mesure plus fine, le couple

μ(a,b)=(a+b,  [b>a])N×{0,1},\mu(a, b) = \big(a + b,\; [\,b \gt a\,]\big) \in \mathbb{N} \times \{0,1\},

ordonné lexicographiquement (on compare d'abord les sommes, puis l'indicateur). Vérifions que chaque appel récursif diminue strictement μ\mu :

  • Cas b>ab \gt a : l'appel passe à (b,a)(b, a). La somme est inchangée, mais l'indicateur passe de 11 à 00 (car a<ba \lt b). Donc μ\mu décroît strictement, et l'appel suivant ne peut pas reprendre cette branche.
  • Cas bab \le a et b0b \neq 0 : l'appel passe à (ab,b)(a-b, b), de somme aa, strictement inférieure à a+ba + b puisque b>0b \gt 0. Donc μ\mu décroît strictement.

Comme N×{0,1}\mathbb{N} \times \{0,1\} muni de l'ordre lexicographique est bien fondé (il n'existe pas de suite infinie strictement décroissante), il n'y a pas de chaîne d'appels infinie : l'algorithme termine. Le cours utilise exactement ce vocabulaire : un ordre bien fondé est un ordre sans suite infinie strictement décroissante, et c'est lui qui autorise l'induction généralisée.

Correction (validation partielle). On raisonne par induction généralisée sur μ(a,b)\mu(a,b).

  • Cas b=0b = 0 : l'algorithme renvoie aa. Or gcd(a,0)=a\gcd(a, 0) = a : la sortie est correcte.
  • Cas b>ab \gt a : l'algorithme renvoie PGCD(b, a). Par hypothèse d'induction appliquée à (b,a)(b,a), dont la mesure est strictement plus petite, cet appel renvoie gcd(b,a)\gcd(b, a). Or le PGCD est symétrique, gcd(b,a)=gcd(a,b)\gcd(b,a) = \gcd(a,b) : la sortie est correcte.
  • Cas bab \le a et b0b \neq 0 : l'algorithme renvoie PGCD(a-b, b). Par hypothèse d'induction, cet appel renvoie gcd(ab,b)\gcd(a-b, b), qui vaut gcd(a,b)\gcd(a,b) par l'identité établie plus haut : la sortie est correcte.

Les trois cas épuisent les situations possibles (si b0b \neq 0 et bab \le a, le troisième cas s'applique). L'algorithme termine et renvoie le PGCD : il est correct. \blacksquare

Vérification. PGCD(12, 18) : b>ab \gt a donc appel de PGCD(18, 12) ; puis PGCD(6, 12) par soustraction, puis PGCD(12, 6) par échange, puis PGCD(6, 6), puis PGCD(0, 6) ; b=0b = 0 donc renvoie 6=gcd(12,18)6 = \gcd(12,18). Correct.

Ce qu'il faut retenir. Le cas de base n'est pas ici « a=b=0a = b = 0 » mais « b=0b = 0 », et la terminaison se prouve par une mesure bien fondée — pas seulement par « la somme diminue ». C'est le prix à payer pour le premier test qui échange les arguments.

#Exercice 4 — Les arbres binaires

Énoncé (TD 3, exercice 6). L'ensemble ABAB des arbres binaires est défini inductivement par : AB\emptyset \in AB ; si gABg \in AB et dABd \in AB alors x=(,g,d)ABx = (\cdot, g, d) \in AB. Soient hh, nn et ff les fonctions donnant respectivement la hauteur, le nombre de nœuds et le nombre de feuilles d'un arbre binaire.

  1. Définir inductivement chacune des fonctions hh, nn et ff.
  2. Montrer que pour tout arbre binaire xABx \in AB, n(x)2h(x)1n(x) \le 2^{h(x)} - 1 et f(x)2h(x)1f(x) \le 2^{h(x)-1}.
  3. Montrer que l'ensemble ABAB des arbres binaires est inductif.
Correction détaillée

1. Définitions inductives. La structure de l'ensemble impose la forme des définitions : une clause pour la base (\emptyset), une clause pour l'étape inductive (le nœud (,g,d)(\cdot, g, d)).

h()=0,h((,g,d))=1+max(h(g),h(d))h(\emptyset) = 0, \qquad h\big((\cdot,g,d)\big) = 1 + \max\big(h(g), h(d)\big)

n()=0,n((,g,d))=1+n(g)+n(d)n(\emptyset) = 0, \qquad n\big((\cdot,g,d)\big) = 1 + n(g) + n(d)

f()=0,f((,g,d))={1si g=d= (le nœud est une feuille)f(g)+f(d)sinonf(\emptyset) = 0, \qquad f\big((\cdot,g,d)\big) = \begin{cases} 1 & \text{si } g = d = \emptyset \ \text{(le nœud est une feuille)} \\ f(g) + f(d) & \text{sinon}\end{cases}

La hauteur du nœud racine ajoute 1 au maximum des hauteurs des sous-arbres ; le nombre de nœuds ajoute 1 aux effectifs des deux sous-arbres ; le nombre de feuilles se transmet par les sous-arbres non vides, une feuille étant un nœud dont les deux sous-arbres sont vides.

2. Bornes. On raisonne par induction structurelle, c'est-à-dire par le principe d'induction sur l'ensemble défini inductivement : la propriété est vérifiée sur la base, puis on montre que si elle est vraie de gg et de dd, elle est vraie de (,g,d)(\cdot,g,d).

Borne sur les nœuds. Pour x=x = \emptyset : n()=0n(\emptyset) = 0 et 2h()1=201=02^{h(\emptyset)} - 1 = 2^0 - 1 = 0, donc l'égalité tient. Pour x=(,g,d)x = (\cdot,g,d) : par hypothèse d'induction, n(g)2h(g)1n(g) \le 2^{h(g)} - 1 et n(d)2h(d)1n(d) \le 2^{h(d)} - 1, d'où

n(x)=1+n(g)+n(d)1+(2h(g)1)+(2h(d)1)=2h(g)+2h(d)1.n(x) = 1 + n(g) + n(d) \le 1 + \big(2^{h(g)} - 1\big) + \big(2^{h(d)} - 1\big) = 2^{h(g)} + 2^{h(d)} - 1.

Or h(g)h(x)1h(g) \le h(x) - 1 et h(d)h(x)1h(d) \le h(x) - 1 par définition de h(x)=1+max(h(g),h(d))h(x) = 1 + \max(h(g),h(d)), donc 2h(g)2h(x)12^{h(g)} \le 2^{h(x)-1} et 2h(d)2h(x)12^{h(d)} \le 2^{h(x)-1}. Il vient

n(x)22h(x)11=2h(x)1.n(x) \le 2 \cdot 2^{h(x)-1} - 1 = 2^{h(x)} - 1. \qquad \blacksquare

Borne sur les feuilles. Pour x=x = \emptyset : f()=0f(\emptyset) = 0 et la borne s'écrit 0210 \le 2^{-1}, ce qui n'a pas de sens : on énonce donc la propriété pour xx \neq \emptyset, ce qui impose h(x)1h(x) \ge 1. Pour une feuille x=(,,)x = (\cdot,\emptyset,\emptyset) : f(x)=1f(x) = 1 et 2h(x)1=20=12^{h(x)-1} = 2^0 = 1 : l'égalité tient. Pour x=(,g,d)x = (\cdot,g,d) non feuille, les deux sous-arbres sont non vides, donc h(g)1h(g) \ge 1 et h(d)1h(d) \ge 1, et l'hypothèse d'induction s'applique :

f(x)=f(g)+f(d)2h(g)1+2h(d)122h(x)2=2h(x)1.f(x) = f(g) + f(d) \le 2^{h(g)-1} + 2^{h(d)-1} \le 2 \cdot 2^{h(x)-2} = 2^{h(x)-1}. \qquad \blacksquare

3. ABAB est inductif. ABAB est défini inductivement par une base (\emptyset) et un ensemble fini d'opérations (g,d(,g,d)g, d \mapsto (\cdot,g,d), d'arité 2). Le cours énonce qu'un ensemble défini inductivement est inductif, c'est-à-dire qu'il est muni d'un bon ordre permettant d'y appliquer le principe d'induction structurelle. C'est précisément ce principe qui vient d'être utilisé en 2.

Vérification. Pour l'arbre parfait de hauteur 3 (racine, 2 enfants, 4 petits-enfants), n=7=231n = 7 = 2^3 - 1 : la borne sur les nœuds est atteinte. Ses feuilles sont au nombre de 4=2314 = 2^{3-1} : la borne sur les feuilles est atteinte aussi. Les deux inégalités sont donc optimales, et l'arbre parfait est l'unique cas d'égalité.

Lien avec la complexité. La borne n2h1n \le 2^h - 1 se réécrit hlog2(n+1)h \ge \log_2(n+1) : la hauteur d'un arbre à nn nœuds ne peut pas descendre sous log2(n+1)\log_2(n+1). C'est cette inégalité qui rend crédible la promesse d'une recherche en O(logn)O(\log n) dans un arbre binaire de recherche équilibré — et qui explique que cette promesse tombe si l'arbre dégénère en liste, cas où h=nh = n.

#Exercice 5 — Compter les opérations d'un programme

Énoncé (TD 4, exercice 3). Quelle est la valeur de la variable compteur à la sortie du sous-programme ci-dessous ?

texttext

1compteur ← 02pour i de 1 à n faire3  pour j de 1 à n faire4    pour k de 1 à n faire5      compteur ← compteur + 1
Correction détaillée

Chaque boucle parcourt exactement nn valeurs. Les trois boucles étant imbriquées, leurs nombres d'itérations se multiplient : le corps de la boucle la plus interne est exécuté

n×n×n=n3n \times n \times n = n^{3}

fois. À la sortie, compteur vaut donc n3n^3.

Le réflexe de comptage. Boucles successives (l'une après l'autre) : les coûts s'additionnent. Boucles imbriquées : les coûts se multiplient. C'est la règle qui transforme un programme en formule, et elle est la base de toute analyse de complexité avant même d'introduire la notation grand-O.

Vérification. Pour n=2n = 2, les triplets (i,j,k)(i,j,k) parcourus sont 23=82^3 = 8 : (1,1,1),(1,1,2),(1,2,1),(1,2,2),(2,1,1),(2,1,2),(2,2,1),(2,2,2)(1,1,1), (1,1,2), (1,2,1), (1,2,2), (2,1,1), (2,1,2), (2,2,1), (2,2,2). Pour n=3n = 3, 2727. Le décompte est bien cubique.

Ordre de grandeur. En comptant une opération par tour, ce programme coûte n3n^3 opérations. Doubler nn multiplie le travail par 88 : c'est la signature d'un algorithme cubique, à éviter dès que nn dépasse quelques milliers.

#Exercice 6 — Chemins monotones dans une grille

Énoncé (TD 4, exercice 7). Un réseau informatique est structuré en grille. Des paquets de données doivent aller du point SS au point DD en suivant les mailles, avec la contrainte supplémentaire que les paquets vont toujours de la gauche vers la droite et du bas vers le haut. Combien d'itinéraires différents peuvent-ils suivre, sachant que la grille comprend pp mailles en largeur et qq mailles en hauteur ?

Correction détaillée

Traduire un chemin en mot. Un itinéraire monotone de SS vers DD est entièrement décrit par la suite de ses déplacements élémentaires : un pas vers la droite (notons-le DD) ou un pas vers le haut (notons-le HH). Parcourir la grille de pp mailles en largeur et qq mailles en hauteur exige exactement

p pas vers la droite et q pas vers le haut,p \text{ pas vers la droite et } q \text{ pas vers le haut},

soit n=p+qn = p + q pas au total. Réciproquement, tout mot de nn lettres sur l'alphabet {D,H}\{D, H\} comportant pp occurrences de DD et qq occurrences de HH décrit un et un seul itinéraire monotone. Il y a donc bijection entre les itinéraires et ces mots.

Compter les mots. Choisir un tel mot, c'est choisir les pp positions occupées par les DD parmi les n=p+qn = p+q positions disponibles : les HH occupent automatiquement les autres. Le nombre cherché est donc le coefficient binomial

(p+qp)=(p+qq)=(p+q)!p!q!.\binom{p+q}{p} = \binom{p+q}{q} = \frac{(p+q)!}{p!\,q!}.

Vérification. Pour p=q=1p = q = 1 (une maille en largeur, une en hauteur), la formule donne (21)=2\binom{2}{1} = 2, et l'on voit bien les deux chemins : DHDH et HDHD. Pour p=2,q=1p = 2, q = 1 : (32)=3\binom{3}{2} = 3, soit DDHDDH, DHDDHD, HDDHDD. Le résultat est cohérent.

Pourquoi c'est un résultat de combinatoire, pas d'énumération. Le nombre de chemins croît de façon exponentielle avec p+qp + q : pour p=q=12p = q = 12 il vaut déjà (2412)=2704156\binom{24}{12} = 2\,704\,156, et il dépasse le milliard dès p=q=18p = q = 18. L'énumération exhaustive coûterait précisément ce nombre d'opérations. Compter au lieu d'énumérer est exactement le geste que le cours met en avant : « avant d'énumérer, il est prudent de dénombrer ».

#Exercice 7 — Dénombrer les graphes non orientés

Énoncé (TD 4, exercice 8). Un graphe non orienté G=(S,A)G = (S, A) est caractérisé par son ensemble de sommets SS et son ensemble d'arêtes (non orientées) AA. Soit Sn={s1,,sn}S_n = \{s_1, \dots, s_n\} un ensemble de nn sommets.

  1. Dessinez les trois graphes non orientés G1G_1, G2G_2 et G3G_3 ayant respectivement S1S_1, S2S_2 et S3S_3 comme ensemble de sommets et dont le nombre d'arêtes est maximal.
  2. Calculez le nombre maximal d'arêtes a(n)a(n) d'un graphe non orienté ayant SnS_n comme ensemble de sommets.
  3. Déduisez-en le nombre g(n)g(n) de graphes non orientés sur l'ensemble de sommets SnS_n.
  4. Application numérique : quel est le nombre de graphes non orientés sur l'ensemble de sommets S3S_3 ?
Correction détaillée

1. Graphes maximaux. G1G_1 est un sommet isolé (aucune arête, a(1)=0a(1) = 0). G2G_2 est un segment : une arête reliant s1s_1 et s2s_2 (a(2)=1a(2) = 1). G3G_3 est un triangle : les trois arêtes {s1,s2}\{s_1,s_2\}, {s1,s3}\{s_1,s_3\}, {s2,s3}\{s_2,s_3\} (a(3)=3a(3) = 3). Ce sont les graphes complets sur 11, 22 et 33 sommets.

2. Nombre maximal d'arêtes. Une arête non orientée est une paire de sommets distincts, donc une partie à 2 éléments de SnS_n. Le nombre maximal d'arêtes est le nombre de ces paires :

a(n)=(n2)=n(n1)2.a(n) = \binom{n}{2} = \frac{n(n-1)}{2}.

Justification : il y a nn choix pour le premier sommet et n1n-1 pour le second, soit n(n1)n(n-1) couples ordonnés ; chaque arête non orientée {si,sj}\{s_i,s_j\} est comptée deux fois, une fois comme (si,sj)(s_i,s_j) et une fois comme (sj,si)(s_j,s_i). D'où n(n1)/2n(n-1)/2. Aucun graphe simple ne peut faire mieux, puisqu'il ne peut contenir que des paires distinctes de SnS_n.

3. Nombre de graphes. Un graphe non orienté sur SnS_n est déterminé par la donnée de son ensemble d'arêtes, c'est-à-dire par le choix d'une partie de l'ensemble des a(n)a(n) paires possibles. Il y a donc autant de graphes que de parties de cet ensemble, soit

g(n)=2a(n)=2n(n1)/2.g(n) = 2^{a(n)} = 2^{\,n(n-1)/2}.

4. Application numérique. a(3)=3×2/2=3a(3) = 3 \times 2 / 2 = 3 et g(3)=23=8g(3) = 2^3 = 8. Les huit graphes sur S3S_3 correspondent aux huit parties de l'ensemble des trois arêtes possibles : le graphe vide, les trois graphes à une arête, les trois graphes à deux arêtes, et le triangle.

Ce que ce résultat enseigne. Le nombre de graphes sur nn sommets est 2n(n1)/22^{n(n-1)/2} : pour n=10n = 10 cela fait déjà 2453,5×10132^{45} \approx 3{,}5 \times 10^{13}, et pour n=30n = 30, environ 2435101312^{435} \approx 10^{131}. Aucun algorithme ne peut énumérer tous les graphes au-delà de quelques dizaines de sommets : c'est exactement le mur exponentiel que décrit le cours de dénombrement, et la raison pour laquelle on cherche des propriétés à prouver plutôt que des cas à parcourir.

#Exercice 8 — Ouvrir un coffre

Énoncé (TD 4, exercice 9). Mme Joublietout a un coffre-fort qui s'ouvre en rentrant une clef à 4 chiffres. Elle a oublié la combinaison mais se rappelle que la somme des quatre chiffres est 10 et qu'aucun des quatre chiffres n'est 0. Combien de combinaisons doit-elle essayer au total ? Combien d'essais si les chiffres peuvent être 0 ?

Correction détaillée

Notons x1,x2,x3,x4x_1, x_2, x_3, x_4 les quatre chiffres de la combinaison. L'énoncé se traduit en un système de contraintes arithmétiques :

x1+x2+x3+x4=10,xi1 (premier cas),xi0 (second cas).x_1 + x_2 + x_3 + x_4 = 10, \qquad x_i \ge 1 \ \text{(premier cas)}, \qquad x_i \ge 0 \ \text{(second cas)}.

Le cours fournit exactement l'outil adapté : le nombre de solutions entières de x1++xn=px_1 + \dots + x_n = p avec xi0x_i \ge 0 est le nombre de combinaisons avec répétition de pp éléments pris parmi nn, soit

Knp=(n+p1n1).K_n^{p} = \binom{n + p - 1}{n - 1}.

Cas 1 — aucun chiffre nul. On se ramène au cas positif ou nul par le changement de variable yi=xi1y_i = x_i - 1, qui est légitime car xi1    yi0x_i \ge 1 \iff y_i \ge 0. En substituant dans l'équation,

(y1+1)+(y2+1)+(y3+1)+(y4+1)=10y1+y2+y3+y4=6.(y_1 + 1) + (y_2 + 1) + (y_3 + 1) + (y_4 + 1) = 10 \quad\Longrightarrow\quad y_1 + y_2 + y_3 + y_4 = 6.

Il reste 4 variables pour un total de 6, donc

(6+4141)=(93)=9×8×73×2×1=84.\binom{6 + 4 - 1}{4 - 1} = \binom{9}{3} = \frac{9 \times 8 \times 7}{3 \times 2 \times 1} = 84.

Cas 2 — les chiffres peuvent être nuls. On applique la formule directement, avec n=4n = 4 et p=10p = 10 :

(10+4141)=(133)=13×12×113×2×1=286.\binom{10 + 4 - 1}{4 - 1} = \binom{13}{3} = \frac{13 \times 12 \times 11}{3 \times 2 \times 1} = 286.

Réponse. Mme Joublietout doit essayer 84 combinaisons dans le premier cas et 286 dans le second. \blacksquare

Le point à ne pas manquer. Le changement de variable porte sur chaque variable : retirer 1 à chacune retire 4 au total, et c'est le second membre qui doit absorber ce retrait (10610 \to 6). Oublier de retirer 4 donne le même (133)=286\binom{13}{3} = 286 dans les deux cas — un signe infaillible que l'erreur a été commise, puisque les deux questions n'ont aucune raison d'avoir la même réponse.

Vérification. Dans le cas 1, les quadruplets ordonnés d'entiers 1\ge 1 de somme 10 se répartissent en familles : (1,1,1,7)(1,1,1,7) et ses 44 permutations, (1,1,2,6)(1,1,2,6) et ses 1212 permutations, etc. Le total de 84 est de l'ordre de grandeur attendu, et il est bien inférieur au total 286286 du cas 2, comme il se doit puisqu'on y impose une contrainte de plus.

#Exercice 9 — Une récurrence complète

Énoncé (TD 5, exercice 1). Résoudre la récurrence suivante, sachant que u0=1u_0 = 1 :

n>0,un=3k=0n1uk+1.\forall n \gt 0, \quad u_n = 3 \sum_{k=0}^{n-1} u_k + 1.

Correction détaillée

Pourquoi on parle de récurrence complète. Le terme unu_n dépend de tous les termes précédents, pas d'un nombre fixé d'entre eux : le cours appelle cela une relation de récurrence complète. La technique associée est la réduction d'ordre par différence : on écrit la relation au rang n+1n+1 et on retranche celle du rang nn, ce qui élimine la somme.

Étape 1 — écrire la relation au rang suivant.

un+1=3k=0nuk+1.u_{n+1} = 3 \sum_{k=0}^{n} u_k + 1.

Étape 2 — isoler la somme. En séparant le dernier terme de la somme :

un+1=3k=0n1uk+3un+1.u_{n+1} = 3 \sum_{k=0}^{n-1} u_k + 3u_n + 1.

Or la relation au rang nn donne 3k=0n1uk=un13\sum_{k=0}^{n-1} u_k = u_n - 1. En substituant :

un+1=(un1)+3un+1=4un.u_{n+1} = (u_n - 1) + 3u_n + 1 = 4u_n.

Étape 3 — résoudre la récurrence d'ordre 1 obtenue. Pour tout n1n \ge 1, un+1=4unu_{n+1} = 4u_n, donc la suite est géométrique de raison 4 à partir de u1u_1 :

un=4n1u1.u_n = 4^{\,n-1} u_1.

Il reste à calculer u1u_1 par la relation d'origine : u1=3u0+1=3×1+1=4u_1 = 3u_0 + 1 = 3 \times 1 + 1 = 4. D'où

un=4n1×4=4npour tout n1,u_n = 4^{\,n-1} \times 4 = 4^{\,n} \quad \text{pour tout } n \ge 1,

et cette formule vaut aussi pour n=0n = 0 puisque 40=1=u04^0 = 1 = u_0. Donc

un=4n pour tout nN.\boxed{u_n = 4^{\,n} \ \text{pour tout } n \in \mathbb{N}.}

Vérification. u0=1=40u_0 = 1 = 4^0. u1=3u0+1=4=41u_1 = 3u_0 + 1 = 4 = 4^1. u2=3(u0+u1)+1=3×5+1=16=42u_2 = 3(u_0 + u_1) + 1 = 3 \times 5 + 1 = 16 = 4^2. u3=3(1+4+16)+1=3×21+1=64=43u_3 = 3(1 + 4 + 16) + 1 = 3 \times 21 + 1 = 64 = 4^3. La formule est confirmée sur quatre rangs.

La méthode en une phrase. Pour une récurrence complète, on écrit la relation au rang n+1n+1, on y reconnaît l'expression du rang nn et on soustrait : la somme disparaît et il ne reste qu'une récurrence d'ordre 1, que l'on sait résoudre.

#Exercice 10 — Récurrences non homogènes et homogène d'ordre 2

Énoncé (TD 5, exercices 2 et 3). Résoudre les récurrences suivantes, sachant que dans les deux premiers cas u0=1u_0 = 1 :

  1. n>0, un=un1+2n\forall n \gt 0,\ u_n = u_{n-1} + 2n.
  2. n>0, un=2un1+1\forall n \gt 0,\ u_n = 2u_{n-1} + 1.
  3. n>1, un=4un13un2\forall n \gt 1,\ u_n = 4u_{n-1} - 3u_{n-2}, avec u0=0u_0 = 0 et u1=1u_1 = 1.
Correction détaillée

1. Suite arithmétique déguisée (a(n)=1a(n) = 1, b(n)=2nb(n) = 2n). On déroule la récurrence en sommant les équations, technique du cours :

un=un1+2nun1=un2+2(n1) u1=u0+21\begin{aligned} u_n &= u_{n-1} + 2n \\ u_{n-1} &= u_{n-2} + 2(n-1) \\ &\ \vdots \\ u_1 &= u_0 + 2 \cdot 1 \end{aligned}

En additionnant membre à membre, les termes intermédiaires s'annulent et il reste

un=u0+2k=1nk=1+2n(n+1)2=1+n(n+1).u_n = u_0 + 2\sum_{k=1}^{n} k = 1 + 2 \cdot \frac{n(n+1)}{2} = 1 + n(n+1).

Donc un=n2+n+1u_n = n^2 + n + 1. Vérification : u1=1+2=3u_1 = 1 + 2 = 3, et la formule donne 1+2=31 + 2 = 3 ; u2=3+4=7u_2 = 3 + 4 = 7, et la formule donne 4+2+1=74 + 2 + 1 = 7. Correct.

2. Suite géométrique translatée (aa, bb constants). On divise par la puissance qui rend la relation homogène. Posons vn=un+1v_n = u_n + 1 : alors

vn=un+1=2un1+2=2(un1+1)=2vn1,v_n = u_n + 1 = 2u_{n-1} + 2 = 2(u_{n-1} + 1) = 2v_{n-1},

et v0=u0+1=2v_0 = u_0 + 1 = 2. Donc (vn)(v_n) est géométrique de raison 2 : vn=22n=2n+1v_n = 2 \cdot 2^n = 2^{n+1}, d'où

un=2n+11.u_n = 2^{\,n+1} - 1.

Vérification : u1=2u0+1=3u_1 = 2u_0 + 1 = 3 et 221=32^2 - 1 = 3 ; u2=2×3+1=7u_2 = 2 \times 3 + 1 = 7 et 231=72^3 - 1 = 7. C'est aussi le coût des tours de Hanoï, que le cours résout exactement de cette façon : T(0)=0T(0) = 0, T(n)=2T(n1)+1T(n) = 2T(n-1) + 1 donne T(n)=2n1T(n) = 2^n - 1.

3. Récurrence homogène d'ordre 2 à coefficients constants. On applique la technique de l'équation caractéristique. On cherche des solutions de la forme un=αnu_n = \alpha^n : en substituant dans un=4un13un2u_n = 4u_{n-1} - 3u_{n-2},

αn=4αn13αn2α2=4α3α24α+3=0.\alpha^n = 4\alpha^{n-1} - 3\alpha^{n-2} \quad\Longrightarrow\quad \alpha^2 = 4\alpha - 3 \quad\Longrightarrow\quad \alpha^2 - 4\alpha + 3 = 0.

Le discriminant vaut Δ=1612=4\Delta = 16 - 12 = 4, d'où deux racines réelles distinctes

α1=422=1,α2=4+22=3.\alpha_1 = \frac{4 - 2}{2} = 1, \qquad \alpha_2 = \frac{4 + 2}{2} = 3.

Le cours donne alors la solution générale un=c1α1n+c2α2nu_n = c_1 \alpha_1^n + c_2 \alpha_2^n, soit un=c1+c23nu_n = c_1 + c_2 \cdot 3^n. Les conditions initiales fixent c1c_1 et c2c_2 :

{u0=c1+c2=0u1=c1+3c2=1\begin{cases} u_0 = c_1 + c_2 = 0 \\ u_1 = c_1 + 3c_2 = 1 \end{cases}

Par différence : 2c2=12c_2 = 1, donc c2=12c_2 = \tfrac12 et c1=12c_1 = -\tfrac12. D'où

un=3n12.\boxed{u_n = \frac{3^{\,n} - 1}{2}}.

Vérification : u0=0u_0 = 0, u1=(31)/2=1u_1 = (3-1)/2 = 1, u2=4u13u0=4u_2 = 4u_1 - 3u_0 = 4 et (91)/2=4(9-1)/2 = 4, u3=4×43×1=13u_3 = 4 \times 4 - 3 \times 1 = 13 et (271)/2=13(27-1)/2 = 13. Correct.

Les trois cas à reconnaître. Le cours classe les récurrences linéaires d'ordre 1 selon a(n)a(n) et b(n)b(n) : a(n)=1a(n) = 1 avec bb constant donne une suite arithmétique (cas 1, avec bb dépendant de nn) ; a(n)a(n) constant donne une suite géométrique, éventuellement translatée (cas 2). Pour l'ordre 2 homogène à coefficients constants, l'équation caractéristique remplace tout : deux racines réelles distinctes donnent c1α1n+c2α2nc_1\alpha_1^n + c_2\alpha_2^n, une racine double donne αn(c1+c2n)\alpha^n(c_1 + c_2 n).

#Exercice 11 — Complexité du tri rapide au pire cas

Énoncé (TD 5, exercice 6). La complexité c(n)c(n) dans le pire des cas de l'algorithme du tri rapide pour trier une liste de nn nombres vérifie l'équation de récurrence ci-dessous (on a un peu triché ici pour simplifier l'expression). Résolvez-la, c'est-à-dire exprimez le terme général c(n)c(n) de la suite (c(n))n2(c(n))_{n \ge 2} en fonction de nn uniquement.

{c(2)=3c(n)=c(n1)+n+1pour n>2\begin{cases} c(2) = 3 \\ c(n) = c(n-1) + n + 1 & \text{pour } n \gt 2 \end{cases}

Correction détaillée

Méthode de sommation. On écrit la relation aux rangs successifs et on additionne, exactement comme pour une récurrence d'ordre 1 avec a(n)=1a(n) = 1 :

c(n)=c(n1)+(n+1)c(n1)=c(n2)+n c(3)=c(2)+4\begin{aligned} c(n) &= c(n-1) + (n+1) \\ c(n-1) &= c(n-2) + n \\ &\ \vdots \\ c(3) &= c(2) + 4 \end{aligned}

En additionnant membre à membre, les termes c(n1),,c(3)c(n-1), \dots, c(3) s'annulent deux à deux et il reste

c(n)=c(2)+k=4n+1k.c(n) = c(2) + \sum_{k=4}^{n+1} k.

Évaluation de la somme. La somme des entiers de 4 à n+1n+1 vaut

k=4n+1k=(n+1)(n+2)2(1+2+3)=(n+1)(n+2)26=n2+3n+2122=n2+3n102.\sum_{k=4}^{n+1} k = \frac{(n+1)(n+2)}{2} - (1 + 2 + 3) = \frac{(n+1)(n+2)}{2} - 6 = \frac{n^2 + 3n + 2 - 12}{2} = \frac{n^2 + 3n - 10}{2}.

D'où

c(n)=3+n2+3n102=n2+3n42.c(n) = 3 + \frac{n^2 + 3n - 10}{2} = \frac{n^2 + 3n - 4}{2}.

Vérification. c(2)=(4+64)/2=3c(2) = (4 + 6 - 4)/2 = 3 : la condition initiale est respectée. c(3)=c(2)+4=7c(3) = c(2) + 4 = 7 et la formule donne (9+94)/2=7(9 + 9 - 4)/2 = 7. c(4)=7+5=12c(4) = 7 + 5 = 12 et (16+124)/2=12(16 + 12 - 4)/2 = 12. c(5)=12+6=18c(5) = 12 + 6 = 18 et (25+154)/2=18(25 + 15 - 4)/2 = 18. La formule est confirmée.

Interprétation. c(n)=n2+3n42c(n) = \frac{n^2 + 3n - 4}{2} est un polynôme de degré 2 : le tri rapide est quadratique dans le pire cas, ce que l'on écrit c(n)=Θ(n2)c(n) = \Theta(n^2). Le cas se produit lorsque le pivot est systématiquement le plus petit ou le plus grand élément, si bien que la partition ne retire qu'un seul élément à chaque tour : la profondeur de récursion devient nn au lieu de log2n\log_2 n. C'est pourquoi les implémentations sérieuses choisissent le pivot au hasard ou en médiane de trois.

Vérification sur le listing du TD. Le pseudo-code de la feuille appelle trirapide(d, pivot-1) puis trirapide(pivot+1, d). La seconde borne devrait être f (la borne droite de la partition) : telle qu'elle est écrite, la récursion de droite repart sur l'intervalle initial. Le listing comporte donc une coquille ; la borne correcte est trirapide(pivot+1, f).

#Exercice 12 — Compter les tas de sable

Énoncé (TD 5, exercice 7). Un tas de sable est une séquence ordonnée d'entiers naturels non nuls, strictement décroissante ; chaque entier représente le nombre de grains empilés à cette position.

  1. On veut compter le nombre T(n)T(n) de tas de sable distincts que l'on peut former sachant que le premier élément de la séquence vaut n>1n \gt 1. Pour n=3n = 3, on peut former (3)(3), (3,1)(3,1), (3,2)(3,2), (3,2,1)(3,2,1), donc T(3)=4T(3) = 4. Calculez T(4)T(4).
  2. Trouvez l'expression de T(n)T(n) en fonction de nn seulement, sachant que T(0)=1T(0) = 1.
Correction détaillée

1. Calcul de T(4)T(4). Énumérons les tas commençant par 4, en classant selon le deuxième élément.

  • Tas réduit à (4)(4) : 1 possibilité.
  • Deuxième élément 3 : la suite des éléments suivants est un tas commençant par 3, soit (3)(3) tout court, ou 33 suivi d'un tas commençant par 1 ou 2. Cela donne (4,3)(4,3), (4,3,2)(4,3,2), (4,3,2,1)(4,3,2,1), (4,3,1)(4,3,1) : 4 possibilités, soit T(3)T(3).
  • Deuxième élément 2 : (4,2)(4,2) et (4,2,1)(4,2,1) : 2 possibilités, soit T(2)T(2).
  • Deuxième élément 1 : (4,1)(4,1) : 1 possibilité, soit T(1)T(1).

Au total T(4)=1+4+2+1=8T(4) = 1 + 4 + 2 + 1 = 8.

2. Relation de récurrence. Généralisons l'observation précédente. Un tas commençant par nn est :

  • soit la séquence réduite (n)(n) : 1 possibilité ;
  • soit nn suivi d'un tas commençant par un élément xx avec 1xn11 \le x \le n-1 : T(x)T(x) possibilités pour chaque xx.

D'où, pour n1n \ge 1,

T(n)=1+x=1n1T(x)=x=0n1T(x),T(n) = 1 + \sum_{x=1}^{n-1} T(x) = \sum_{x=0}^{n-1} T(x),

la dernière égalité utilisant T(0)=1T(0) = 1, que le premier cas (n)(n) réalise précisément. Vérification : T(1)=T(0)=1T(1) = T(0) = 1 (seul le tas (1)(1)) ; T(2)=T(0)+T(1)=2T(2) = T(0) + T(1) = 2 (les tas (2)(2) et (2,1)(2,1)) ; T(3)=1+1+2=4T(3) = 1 + 1 + 2 = 4, conforme à l'énoncé.

3. Résolution. La relation T(n)=x=0n1T(x)T(n) = \sum_{x=0}^{n-1} T(x) est une récurrence complète, du même type que l'exercice 9. On l'écrit au rang n+1n+1 et on soustrait :

T(n+1)=x=0nT(x)=x=0n1T(x)+T(n)=T(n)+T(n)=2T(n).T(n+1) = \sum_{x=0}^{n} T(x) = \sum_{x=0}^{n-1} T(x) + T(n) = T(n) + T(n) = 2\,T(n).

La suite est donc géométrique de raison 2 à partir de T(0)=1T(0) = 1 :

T(n)=2n1 pour n1,T(0)=1.T(n) = 2^{\,n-1} \ \text{pour } n \ge 1, \qquad T(0) = 1.

Vérification : T(1)=1=20T(1) = 1 = 2^0, T(2)=2=21T(2) = 2 = 2^1, T(3)=4=22T(3) = 4 = 2^2, T(4)=8=23T(4) = 8 = 2^3. Conforme.

Ce que le résultat dit. Les tas de sable à premier élément nn sont en bijection avec les parties de {1,,n1}\{1, \dots, n-1\} : un tas est déterminé par le choix de l'ensemble des positions occupées, ce qui explique le 2n12^{n-1} et fait écho au comptage des parties d'un ensemble à n1n-1 éléments. Le comptage combinatoire et la récurrence disent ici la même chose.

#Ce que ces annales vérifient

  • Induction : cas de base multiples quand l'hérédité recule de kk (exercice 1) ; jonction obligatoire entre cas de base et hérédité (exercice 2) ; mesure bien fondée pour la terminaison (exercice 3) ; induction structurelle sur un ensemble défini inductivement (exercice 4).
  • Dénombrement : boucles imbriquées et multiplication des coûts (exercice 5) ; bijection entre chemins et mots, coefficients binomiaux (exercice 6) ; nombre de graphes 2n(n1)/22^{n(n-1)/2} (exercice 7) ; combinaisons avec répétition et changement de variable (exercice 8).
  • Récurrences : récurrence complète réduite par différence (exercices 9, 12) ; suites arithmétiques, géométriques et translatées (exercice 10) ; équation caractéristique d'ordre 2 (exercice 10) ; récurrence de coût d'un algorithme récursif (exercice 11).