Maths Post-Bac Ouvrir l'app

Exercices corrigés — Recherche opérationnelle & graphes

Analyse · 18 exercices-types du palier socle

L2L3Maths ingénieur

Chaque exercice donne l'énoncé, des indices progressifs et la correction rédigée étape par étape. Ouvre les blocs seulement après avoir cherché.

Revoir le cours : Recherche opérationnelle & graphes Définitions, méthodes et exemples corrigés du chapitre.

Degrés & lemme des poignées

CalculDifficulté 3/5

Soit le graphe non orienté de sommets {0,1,2,3,4}\{0,1,2,3,4\} et d'arêtes 01,02,12,23,3401,02,12,23,34. Écrire sa matrice d'adjacence, donner les degrés, et vérifier le lemme des poignées.

Indices (3)

La matrice d'adjacence AA est symétrique : Aij=1A_{ij}=1 si ii et jj sont reliés.

Le degré d'un sommet est la somme de sa ligne dans AA.

Lemme des poignées : ∑vdeg⁡(v)=2∣E∣\sum_v\deg(v)=2\lvert E\rvert.

Correction détaillée
L'idée directrice

Un graphe est la structure de base de tout ce chapitre : des sommets reliés par des arêtes. Pour le manipuler par le calcul, il faut le représenter, et la représentation la plus directe est la matrice d'adjacence.

Aij={1s’il y a une areˆte entre i et j0sinonA_{ij}=\begin{cases}1&\text{s'il y a une arête entre }i\text{ et }j\\ 0&\text{sinon}\end{cases}

Le degré d'un sommet est son nombre de voisins. Et le lemme des poignées de main relie les deux : il dit que la somme des degrés vaut le double du nombre d'arêtes.

Étape 1 — la matrice d'adjacence

Sommets {0,1,2,3,4}\{0,1,2,3,4\}, arêtes 0101, 0202, 1212, 2323, 3434.

Le graphe est non orienté, donc chaque arête ijij produit deux 11 : en (i,j)(i,j) et en (j,i)(j,i). La matrice est donc symétrique.

A=(0110010100110100010100010)A=\begin{pmatrix}0&1&1&0&0\\1&0&1&0&0\\1&1&0&1&0\\0&0&1&0&1\\0&0&0&1&0\end{pmatrix}

Contrôles de forme, à faire systématiquement :

  • la matrice est symétrique ✓ (graphe non orienté) ;
  • la diagonale est nulle ✓ (aucune boucle : pas d'arête d'un sommet vers lui-même) ;
  • il y a 2×5=102\times5=10 coefficients égaux à 11 ✓ (deux par arête).
Étape 2 — les degrés

Le degré d'un sommet se lit sur sa ligne : c'est la somme des coefficients.

sommet voisins degré
00 1,21,2 22
11 0,20,2 22
22 0,1,30,1,3 3\mathbf{3}
33 2,42,4 22
44 33 1\mathbf{1}

Le sommet 22 est le plus connecté (c'est un « carrefour »), le sommet 44 est une feuille — il n'a qu'un seul voisin.

Étape 3 — le lemme des poignées de main
∑vdeg⁡(v)=2 ∣E∣\sum_{v}\deg(v)=2\,\lvert E\rvert

Vérification :

2+2+3+2+1=10,2×5=10.✓2+2+3+2+1=\mathbf{10},\qquad 2\times5=\mathbf{10}.\qquad\checkmark

Pourquoi c'est vrai — et l'argument est joli : chaque arête a deux extrémités, donc elle contribue 11 au degré de chacune, soit 22 au total. En sommant sur toutes les arêtes, on compte donc chaque arête deux fois.

Le nom vient de l'interprétation : dans une réunion, la somme des nombres de mains serrées par chaque personne vaut le double du nombre de poignées de main échangées.

La conséquence à connaître : le nombre de sommets de degré IMPAIR est PAIR

Séparons la somme selon la parité des degrés :

∑deg⁡ pairdeg⁡(v)⏟pair+∑deg⁡ impairdeg⁡(v)=2∣E∣⏟pair.\underbrace{\sum_{\deg\ \text{pair}}\deg(v)}_{\text{pair}}+\sum_{\deg\ \text{impair}}\deg(v)=\underbrace{2\lvert E\rvert}_{\text{pair}}.

La seconde somme est donc paire. Or c'est une somme de nombres impairs : elle n'est paire que s'il y en a un nombre pair.

Il y a toujours un nombre PAIR de sommets de degreˊ impair.\boxed{\text{Il y a toujours un nombre PAIR de sommets de degré impair.}}

Vérification ici : les degrés sont 2,2,3,2,12,2,3,2,1 — deux impairs (33 et 11), donc un nombre pair ✓

Ce corollaire est loin d'être anecdotique : c'est lui qui décide de l'existence d'un parcours eulérien (exercice A4).

Contrôle par la matrice

On peut aussi lire les degrés matriciellement : le vecteur des degrés est A1⃗A\vec{\mathbf 1}, où 1⃗=(1,1,1,1,1)T\vec{\mathbf 1}=(1,1,1,1,1)^{\mathsf T}.

A1⃗=(0+1+1+0+01+0+1+0+01+1+0+1+00+0+1+0+10+0+0+1+0)=(22321) ✓A\vec{\mathbf 1}=\begin{pmatrix}0+1+1+0+0\\1+0+1+0+0\\1+1+0+1+0\\0+0+1+0+1\\0+0+0+1+0\end{pmatrix}=\begin{pmatrix}2\\2\\3\\2\\1\end{pmatrix}\ \checkmark

Et le nombre d'arêtes vaut 121⃗TA1⃗=102=5\tfrac12\vec{\mathbf 1}^{\mathsf T}A\vec{\mathbf 1}=\tfrac{10}{2}=5 ✓

Autre propriété utile : le coefficient (i,j)(i,j) de AkA^k compte le nombre de chemins de longueur exactement kk entre ii et jj. C'est ce qui fait de la matrice d'adjacence un outil de calcul, et pas seulement de rangement.

Réponse : la matrice est symétrique à diagonale nulle avec dix 11 ; les degrés sont (2,2,3,2,1)(2,2,3,2,1), de somme 10=2×510=2\times5 — le lemme des poignées de main est vérifié.

Réponse. Degrés (2,2,3,2,1)(2,2,3,2,1), ∑=10=2∣E∣\sum=10=2\lvert E\rvert avec ∣E∣=5\lvert E\rvert=5. (Recoupement : somme des coefficients de AA =10=2∣E∣=10=2\lvert E\rvert ✓)
Faire cet exercice dans l'app →

Parcours BFS et DFS

CalculDifficulté 3/5

Sur le graphe précédent (arêtes 01,02,12,23,3401,02,12,23,34), donner l'ordre de visite par BFS puis par DFS depuis le sommet 00 (voisins explorés par ordre croissant).

Indices (3)

BFS : file d'attente, on visite tous les voisins avant d'aller plus loin.

DFS : pile (ou récursion), on plonge le plus loin possible.

Voisins de 00 : {1,2}\{1,2\} ; de 22 : {0,1,3}\{0,1,3\} ; etc.

Correction détaillée
Les deux parcours

Explorer un graphe, c'est visiter tous ses sommets à partir d'un point de départ. Deux stratégies, qui diffèrent par une seule structure de données :

structure comportement
BFS (parcours en largeur) FILE — premier entré, premier sorti explore par couches : tous les voisins, puis les voisins des voisins
DFS (parcours en profondeur) PILE — dernier entré, premier sorti s'enfonce aussi loin que possible, puis revient en arrière

Le graphe : sommets {0,1,2,3,4}\{0,1,2,3,4\}, arêtes 0101, 0202, 1212, 2323, 3434, avec les listes de voisins triées par ordre croissant :

0:{1,2},1:{0,2},2:{0,1,3},3:{2,4},4:{3}.0:\{1,2\},\quad 1:\{0,2\},\quad 2:\{0,1,3\},\quad 3:\{2,4\},\quad 4:\{3\}.
BFS, pas à pas

On part de 00. La file contient les sommets découverts mais pas encore traités.

étape on traite on découvre file après visités
1 00 11, 22 [1,2][1,2] 00
2 11 rien (00 vu, 22 déjà découvert) [2][2] 0,10,1
3 22 33 [3][3] 0,1,20,1,2
4 33 44 [4][4] 0,1,2,30,1,2,3
5 44 rien [ ][\,] 0,1,2,3,40,1,2,3,4
BFS:0, 1, 2, 3, 4\boxed{\text{BFS} : 0,\ 1,\ 2,\ 3,\ 4}

Le point à ne pas rater, étape 2 : on ne rajoute pas 22 une seconde fois. Un sommet est marqué dès qu'il est découvert, pas quand il est traité — sinon il entrerait plusieurs fois dans la file.

DFS, pas à pas

On part de 00 et on s'enfonce, en prenant toujours le plus petit voisin non visité.

on est en voisins non visités on va en
00 1,21,2 →1\to1
11 22 (00 est vu) →2\to2
22 33 (0,10,1 vus) →3\to3
33 44 (22 vu) →4\to4
44 aucun retour arrière
DFS:0, 1, 2, 3, 4\boxed{\text{DFS} : 0,\ 1,\ 2,\ 3,\ 4}
⚠️ Les deux ordres sont IDENTIQUES — ce qui ne veut pas dire que les parcours le sont

C'est le fait le plus instructif de l'exercice, et il faut savoir l'expliquer.

Sur ce graphe, BFS et DFS visitent les sommets dans le même ordre. Ce n'est pas une erreur, c'est une coïncidence de structure : le graphe est presque un chemin, il n'offre pas de « choix » qui ferait diverger les deux stratégies.

Mais les ARBRES d'exploration diffèrent, et c'est là qu'on voit la différence :

sommet père en BFS père en DFS
11 00 00
2\mathbf{2} 0\mathbf{0} 1\mathbf{1}
33 22 22
44 33 33

Le sommet 22 est atteint depuis 00 en BFS, depuis 11 en DFS. Conséquence sur les profondeurs :

sommet profondeur BFS profondeur DFS
00 00 00
11 11 11
22 1\mathbf{1} 2\mathbf{2}
33 22 33
44 33 44

Les profondeurs BFS sont les vraies distances en nombre d'arêtes ; les profondeurs DFS ne le sont pas.

Ce que chacun sert à faire

C'est la seule chose à retenir vraiment, parce qu'elle décide du choix en pratique.

BFS DFS
plus courts chemins en nombre d'arêtes détection de cycles
niveaux / couches (réseaux sociaux : « à 2 amis de distance ») tri topologique (exercice A6)
propagation, diffusion composantes fortement connexes
il visite 22 à distance 11, ce qui est exact il le voit à profondeur 22, ce qui n'est pas la distance

La propriété fondamentale du BFS : il découvre les sommets par distance croissante à la source. C'est ce qui en fait l'algorithme des plus courts chemins quand toutes les arêtes ont le même poids — et c'est exactement ce que généralise Dijkstra (exercice B1) pour des poids quelconques.

Complexité : les deux sont en O(∣V∣+∣E∣)O(\lvert V\rvert+\lvert E\rvert) — chaque sommet est traité une fois, chaque arête examinée deux fois (une par extrémité).

Réponse : BFS et DFS donnent tous deux 0,1,2,3,40,1,2,3,4 ; mais leurs arbres d'exploration diffèrent — en BFS le sommet 22 a pour père 00 (profondeur 11), en DFS il a pour père 11 (profondeur 22).

Réponse. BFS == DFS =(0,1,2,3,4)=(0,1,2,3,4). (Recoupement scipy breadth_first_order/depth_first_order : [0,1,2,3,4][0,1,2,3,4] pour les deux ✓)
Faire cet exercice dans l'app →

Composantes connexes

CalculDifficulté 3/5

Le graphe non orienté de sommets {0,1,2,3,4}\{0,1,2,3,4\} a pour arêtes 01,02,12,3401,02,12,34. Combien a-t-il de composantes connexes ? Les décrire.

Indices (3)

Une composante connexe est un groupe maximal de sommets reliés entre eux.

Lancer un parcours depuis un sommet : il découvre toute sa composante.

Recommencer depuis un sommet non encore visité.

Correction détaillée
L'idée directrice

Une composante connexe est un « morceau » du graphe : un ensemble maximal de sommets reliés entre eux par des chemins. Deux sommets de composantes différentes ne peuvent jamais être joints.

La méthode est mécanique : on lance un parcours (BFS ou DFS, exercice A2) depuis un sommet non encore visité, ce qui découvre toute sa composante ; puis on recommence depuis un sommet resté non visité, et ainsi de suite jusqu'à épuisement.

Étape 1 — le graphe

Sommets {0,1,2,3,4}\{0,1,2,3,4\}, arêtes 0101, 0202, 1212, 3434.

Listes de voisins :

0:{1,2},1:{0,2},2:{0,1},3:{4},4:{3}.0:\{1,2\},\qquad 1:\{0,2\},\qquad 2:\{0,1\},\qquad 3:\{4\},\qquad 4:\{3\}.

⚠️ Comparer avec l'exercice A1 : le graphe est le même, à une arête près — l'arête 2323 a disparu. C'était précisément le pont entre les deux moitiés.

Étape 2 — dérouler l'algorithme

Premier parcours, depuis 00 (le plus petit sommet non visité) :

on traite on découvre
00 11, 22
11 rien de neuf
22 rien de neuf

Composante trouvée : {0,1,2}\{0,1,2\}. Le parcours s'arrête — il ne peut pas sortir.

Deuxième parcours, depuis 33 (plus petit sommet non encore visité) :

on traite on découvre
33 44
44 rien de neuf

Composante trouvée : {3,4}\{3,4\}.

Tous les sommets sont visités, l'algorithme s'arrête.

2 composantes connexes:{0,1,2} et {3,4}\boxed{2\text{ composantes connexes} : \{0,1,2\}\ \text{et}\ \{3,4\}}
Décrire les composantes
composante sommets arêtes structure
C1C_1 {0,1,2}\{0,1,2\} 0101, 0202, 1212 triangle K3K_3 — complet
C2C_2 {3,4}\{3,4\} 3434 arête simple K2K_2

C1C_1 est un graphe complet : ses trois sommets sont deux à deux adjacents. C2C_2 est le plus petit graphe connexe non trivial.

Contrôles :

  • 3+2=53+2=5 sommets ✓ — les composantes partitionnent l'ensemble des sommets ;
  • 3+1=43+1=4 arêtes ✓ — toute arête est à l'intérieur d'une composante, jamais entre deux ;
  • il n'existe aucun chemin de 00 à 33 : c'est ce qui définit deux composantes distinctes.
Les bornes à connaître

Le nombre cc de composantes est encadré par des propriétés simples du graphe.

Un graphe à nn sommets et mm arêtes vérifie c≥n−mc\ge n-m. Ici 5−4=15-4=1, et l'on a c=2≥1c=2\ge1 ✓ (chaque arête ne peut fusionner que deux composantes au plus, donc en partant de nn composantes isolées, mm arêtes en suppriment au plus mm.)

Deux conséquences immédiates :

affirmation vraie ?
un graphe connexe (c=1c=1) a au moins n−1n-1 arêtes oui
un graphe à n−1n-1 arêtes est connexe non — c'est notre exemple ! 55 sommets, 44 arêtes, et pourtant 22 composantes

Notre graphe est le contre-exemple : il a bien n−1=4n-1=4 arêtes, mais une est « gaspillée » dans le triangle (qui n'a besoin que de 22 arêtes pour être connexe) au lieu de servir de pont.

connexe ⟹ m≥n−1,mais la reˊciproque est FAUSSE.\text{connexe}\ \Longrightarrow\ m\ge n-1,\qquad\text{mais la réciproque est FAUSSE.}

Le cas d'égalité m=n−1m=n-1 avec connexité caractérise les arbres — c'est l'objet de l'exercice E3.

Ce que ça sert à faire

La connexité n'est pas une curiosité théorique : c'est souvent la première question à poser sur un réseau.

domaine ce que dit une composante
réseau informatique des machines qui ne peuvent pas communiquer
réseau social des groupes sans aucune relation commune
routier des zones inaccessibles l'une depuis l'autre
résolution de systèmes des blocs indépendants, traitables séparément

Et pour tous les algorithmes du chapitre, la question est préalable : chercher un plus court chemin de 00 à 33 (exercice B1) n'a pas de sens ici, il n'y en a aucun. Un algorithme de plus court chemin rendra +∞+\infty — ce qui est la bonne réponse, mais il faut savoir la lire.

Complexité : un seul parcours global, donc O(n+m)O(n+m) — on ne visite chaque sommet et chaque arête qu'une fois, quel que soit le nombre de composantes.

Réponse : 22 composantes connexes — {0,1,2}\{0,1,2\}, qui est un triangle, et {3,4}\{3,4\}, qui est une simple arête ; aucun chemin ne relie les deux.

Réponse. 22 composantes : {0,1,2}\{0,1,2\} et {3,4}\{3,4\}. (Recoupement scipy connected_components : 22 composantes, labels [0,0,0,1,1][0,0,0,1,1] ✓)
Faire cet exercice dans l'app →

Ponts de Königsberg (Euler)

DémonstrationDifficulté 3/5

Le multigraphe des ponts de Königsberg a 44 sommets de degrés 3,3,3,53,3,3,5. Peut-on faire une promenade empruntant chaque pont une seule fois ? Comparer avec un cycle C4C_4.

Indices (3)

Critère d'Euler : un chemin eulérien existe ssi le graphe connexe a 00 ou 22 sommets de degré impair.

Compter les sommets de degré impair de Königsberg.

Un circuit fermé exige 00 sommet impair.

Correction détaillée
Le problème historique

Königsberg, 17361736 : quatre quartiers reliés par sept ponts. Les habitants cherchaient une promenade empruntant chaque pont une fois et une seule. Euler a montré que c'était impossible — et sa démonstration a fondé la théorie des graphes.

Le point remarquable est que la réponse ne demande aucune recherche exhaustive : elle se lit sur les degrés, en une ligne.

Le théorème d'Euler

Pour un graphe connexe :

condition sur les degrés ce qui existe
tous pairs un cycle eulérien (on revient au point de départ)
exactement 2 impairs un chemin eulérien (départ et arrivée = les deux sommets impairs)
plus de 2 impairs rien — ni cycle, ni chemin

Rappel de l'exercice A1 : le nombre de sommets de degré impair est toujours pair. Les seuls cas possibles sont donc 00, 22, 44, 66… impairs.

Pourquoi la parité décide

L'argument est d'une simplicité totale, et il vaut mieux le comprendre que le retenir.

Considérons un sommet intermédiaire du parcours — un sommet qui n'est ni le départ ni l'arrivée. Chaque fois qu'on y entre par un pont, il faut en ressortir par un autre. Les ponts de ce sommet se regroupent donc par paires : son degré est nécessairement pair.

Restent le départ et l'arrivée. Au départ, on sort une fois de plus qu'on n'entre ; à l'arrivée, l'inverse. Ces deux sommets-là peuvent donc être de degré impair.

Au plus DEUX sommets peuvent eˆtre de degreˊ impair, et ce sont les extreˊmiteˊs.\boxed{\text{Au plus DEUX sommets peuvent être de degré impair, et ce sont les extrémités.}}

Si l'on veut un cycle (départ = arrivée), ce sommet-là redevient intermédiaire : tous les degrés doivent être pairs.

Application à Königsberg

Degrés : 33, 33, 33, 55.

nombre de sommets de degreˊ IMPAIR=4.\text{nombre de sommets de degré IMPAIR}=\mathbf{4}.
4>2⟹IMPOSSIBLE — ni cycle ni chemin euleˊrien.4>2\qquad\Longrightarrow\qquad \boxed{\text{IMPOSSIBLE — ni cycle ni chemin eulérien.}}

Contrôle par le lemme des poignées de main (exercice A1) : 3+3+3+5=14=2×73+3+3+5=14=2\times7, il y a donc bien sept ponts ✓ Et 44 est bien un nombre pair de sommets impairs, comme le veut le corollaire ✓

La réponse est donc NON, et Euler l'a établie sans essayer un seul itinéraire — c'est ce qui fait la force de l'argument.

Comparaison avec le cycle $C_4$

Le cycle à quatre sommets C4C_4 : arêtes 0101, 1212, 2323, 3030.

sommet voisins degré
00 1,31,3 22
11 0,20,2 22
22 1,31,3 22
33 2,02,0 22
nombre de degreˊs impairs=0⟹cycle euleˊrien.\text{nombre de degrés impairs}=\mathbf{0}\qquad\Longrightarrow\qquad \textbf{cycle eulérien}.

Et il est évident : le parcours 0→1→2→3→00\to1\to2\to3\to0 emprunte les quatre arêtes, une fois chacune, et revient au départ ✓

Contrôle : 2+2+2+2=8=2×42+2+2+2=8=2\times4 ✓

Le contraste est net : les deux graphes sont connexes, les deux ont un nombre pair de sommets impairs — mais l'un en a 44 et l'autre 00. C'est ce seul décompte qui décide.

Un cas intermédiaire, pour compléter

Reprenons le graphe de l'exercice A1 (arêtes 0101, 0202, 1212, 2323, 3434), de degrés 2,2,3,2,12,2,3,2,1.

impairs:les sommets 2 et 4 ⟹ 2 impairs.\text{impairs} : \text{les sommets }2\text{ et }4\ \Longrightarrow\ \mathbf{2}\ \text{impairs}.

Il existe donc un chemin eulérien, d'extrémités 22 et 44. Vérifions en l'exhibant :

2→0→1→2→3→4.2\to0\to1\to2\to3\to4.

Arêtes empruntées : 2020, 0101, 1212, 2323, 3434 — les cinq, chacune une fois ✓ Et l'on part bien de 22 pour arriver en 44, les deux sommets impairs ✓

⚠️ On ne peut pas revenir au départ : il n'y a pas de cycle eulérien, seulement un chemin.

⚠️ Ne pas confondre avec le circuit hamiltonien, qui passe par chaque SOMMET une fois — celui-là n'a aucun critère simple et est NP-difficile (exercice D6). Euler pour les arêtes : facile. Hamilton pour les sommets : difficile. La différence entre les deux problèmes est l'une des plus frappantes du chapitre.

Réponse : NON pour Königsberg — ses quatre sommets de degré impair (3,3,3,53,3,3,5) interdisent tout parcours eulérien ; alors que C4C_4, dont les quatre degrés valent 22, admet le cycle eulérien 0→1→2→3→00\to1\to2\to3\to0.

Réponse. Impossible à Königsberg (44 sommets de degré impair >2>2) ; C4C_4 admet un circuit eulérien (00 impair). (Recoupement : critère d'Euler vérifié ✓)
Faire cet exercice dans l'app →

Graphe biparti & cycle impair

DémonstrationDifficulté 3/5

Montrer que le cycle C4C_4 est biparti (donc 22-coloriable) mais que le triangle C3C_3 ne l'est pas.

Indices (3)

Biparti   ⟺  \iff 22-coloriable   ⟺  \iff aucun cycle de longueur impaire.

Tenter une 22-coloration en alternant les couleurs le long du cycle.

Sur un cycle impair, l'alternance se contredit au bouclage.

Correction détaillée
La notion

Un graphe est biparti si l'on peut partager ses sommets en deux groupes tels que toute arête relie un groupe à l'autre — jamais deux sommets du même groupe.

C'est exactement une coloration à 2 couleurs : on peint un groupe en rouge, l'autre en bleu, et aucune arête ne joint deux sommets de même couleur.

biparti⟺2-coloriable⟺χ≤2.\text{biparti}\quad\Longleftrightarrow\quad 2\text{-coloriable}\quad\Longleftrightarrow\quad \chi\le2.
$C_4$ est biparti

Le cycle C4C_4 : sommets {0,1,2,3}\{0,1,2,3\}, arêtes 0101, 1212, 2323, 3030.

La partition :  X={0,2}\ X=\{0,2\} et Y={1,3}Y=\{1,3\}.

Vérifions chaque arête — c'est le seul contrôle qui vaille :

arête de vers traverse ?
0101 0∈X0\in X 1∈Y1\in Y ✓
1212 1∈Y1\in Y 2∈X2\in X ✓
2323 2∈X2\in X 3∈Y3\in Y ✓
3030 3∈Y3\in Y 0∈X0\in X ✓

Les quatre arêtes traversent ⟹\Longrightarrow C4C_4 est biparti, donc 22-coloriable.

Contrôle de complétude : XX et YY sont disjoints et leur réunion est l'ensemble des sommets ✓ Et aucune arête n'est interne : il n'y a ni 0202 ni 1313 dans la liste ✓

$C_3$ ne l'est PAS

Le triangle C3C_3 : sommets {0,1,2}\{0,1,2\}, arêtes 0101, 1212, 2020.

Démonstration par l'absurde. Supposons une partition en deux groupes.

  • 00 est dans un groupe, disons XX ;
  • l'arête 0101 force 11 dans l'autre groupe, YY ;
  • l'arête 1212 force 22 dans le groupe de 00, donc XX ;
  • mais alors l'arête 2020 relie 2∈X2\in X à 0∈X0\in X : deux sommets du même groupe.

Contradiction ⟹\Longrightarrow C3C_3 n'est pas biparti, et χ(C3)=3\chi(C_3)=3.

C'est aussi ce qu'on voit en coloriant : 00 rouge, 11 bleu, 22 doit différer des deux — il faut une troisième couleur.

Le critère général — c'est le résultat à retenir

Théorème. Un graphe est biparti si et seulement si il ne contient aucun cycle de longueur impaire.

Pourquoi. En parcourant un cycle, la couleur alterne à chaque arête : rouge, bleu, rouge, bleu… Après kk arêtes on a la couleur de départ si et seulement si kk est pair. Un cycle impair ramènerait donc au point de départ avec la mauvaise couleur — impossible.

graphe cycles biparti ? χ\chi
C3C_3 longueur 3\mathbf{3}, impaire non 33
C4C_4 longueur 44, paire oui 22
C5C_5 longueur 5\mathbf{5}, impaire non 33
C6C_6 longueur 66, paire oui 22
arbre (au moins une arête) aucun cycle toujours oui 22

Règle générale des cycles : χ(Cn)=2\chi(C_n)=2 si nn est pair, 33 si nn est impair. On la retrouvera à l'exercice D4.

Les arbres sont bipartis par vacuité — sans cycle, il n'y a pas de cycle impair. On les colorie par la parité de la profondeur.

Comment le TESTER en pratique

L'algorithme est un simple BFS (exercice A2) qui colorie au passage :

  1. colorier le sommet de départ en rouge ;
  2. à chaque découverte, colorier le nouveau sommet de la couleur opposée à son père ;
  3. si l'on rencontre une arête entre deux sommets déjà coloriés de la même couleur : le graphe n'est pas biparti, et cette arête ferme un cycle impair.

Sur C3C_3 : 00 rouge, 11 bleu (via 0101), 22 rouge (via 1212). Puis l'arête 2020 relie deux sommets rouges ⟹\Longrightarrow détection ✓

Sur C4C_4 : 00 rouge, 11 bleu, 22 rouge, 33 bleu. L'arête 3030 relie bleu et rouge ⟹\Longrightarrow aucun conflit ✓

Coût : O(n+m)O(n+m), celui d'un parcours — c'est-à-dire très peu.

Ce que ça sert à faire

La bipartition n'est pas qu'un exercice de coloriage : c'est la structure de tous les problèmes d'appariement.

situation groupe XX groupe YY
affectation de tâches agents tâches
emplois du temps cours créneaux
mariages stables candidats postes
recommandation utilisateurs produits

Et c'est décisif algorithmiquement : le couplage maximal, qui reste polynomial en général mais exige l'algorithme « des fleurs » d'Edmonds, devient simple sur un graphe biparti (exercice C3), par réduction au flot maximal.

⚠️ La différence avec la coloration générale est frappante : tester si χ≤2\chi\le2 coûte O(n+m)O(n+m), alors que tester si χ≤3\chi\le3 est NP-complet (exercice D6). Une seule couleur de plus fait basculer le problème.

Réponse : C4C_4 est biparti, avec X={0,2}X=\{0,2\} et Y={1,3}Y=\{1,3\} — ses quatre arêtes traversent ; C3C_3 ne l'est pas, car son cycle de longueur 33 est impair, et χ(C3)=3\chi(C_3)=3.

Réponse. C4C_4 biparti ({0,2}∣{1,3}\{0,2\}\mid\{1,3\}) ; C3C_3 non (cycle impair). (Recoupement : parcours de coloration — succès sur C4C_4, conflit sur C3C_3 ✓)
Faire cet exercice dans l'app →

Tri topologique d'un DAG

CalculDifficulté 3/5

Pour le graphe orienté d'arcs 0→20\to2, 1→21\to2, 2→32\to3, 2→42\to4, donner un tri topologique. Que se passe-t-il si on ajoute l'arc 3→13\to1 ?

Indices (3)

Algorithme de Kahn : retirer un sommet de degré entrant nul, recommencer.

Degrés entrants : 0 ⁣: ⁣00\!:\!0, 1 ⁣: ⁣01\!:\!0, 2 ⁣: ⁣22\!:\!2, 3 ⁣: ⁣13\!:\!1, 4 ⁣: ⁣14\!:\!1.

Un cycle empêche tout sommet d'avoir un degré entrant nul à un moment.

Correction détaillée
L'idée directrice

Un tri topologique ordonne les sommets d'un graphe orienté de sorte que chaque arc aille de gauche à droite : si u→vu\to v, alors uu apparaît avant vv.

C'est l'ordre dans lequel exécuter des tâches qui dépendent les unes des autres.

Un tri topologique existe si et seulement si le graphe est un DAG — sans circuit.\boxed{\text{Un tri topologique existe si et seulement si le graphe est un DAG — sans circuit.}}

DAG = Directed Acyclic Graph, graphe orienté acyclique.

Étape 1 — les degrés entrants

Arcs : 0→20\to2, 1→21\to2, 2→32\to3, 2→42\to4.

Le degré entrant d'un sommet est son nombre de prédécesseurs — c'est-à-dire le nombre de conditions à remplir avant de pouvoir le traiter.

sommet prédécesseurs degré entrant
00 aucun 0\mathbf{0}
11 aucun 0\mathbf{0}
22 00, 11 22
33 22 11
44 22 11

Les sommets de degré entrant 00 sont ceux qu'on peut traiter immédiatement : ici 00 et 11.

Étape 2 — l'algorithme de Kahn

Le principe : on retire un sommet sans prédécesseur, on met à jour les degrés entrants, et on recommence.

étape disponibles on sort on décrémente sortie
1 {0,1}\{0,1\} 00 deg⁡−(2):2→1\deg^-(2):2\to1 00
2 {1}\{1\} 11 deg⁡−(2):1→0\deg^-(2):1\to\mathbf{0} 0,10,1
3 {2}\{2\} 22 deg⁡−(3):1→0\deg^-(3):1\to0, deg⁡−(4):1→0\deg^-(4):1\to0 0,1,20,1,2
4 {3,4}\{3,4\} 33 — 0,1,2,30,1,2,3
5 {4}\{4\} 44 — 0,1,2,3,40,1,2,3,4
tri topologique:0, 1, 2, 3, 4\boxed{\text{tri topologique} : 0,\ 1,\ 2,\ 3,\ 4}

Vérification — chaque arc doit aller de gauche à droite :

arc position source position cible OK ?
0→20\to2 1re1^{\text{re}} 3e3^{\text{e}} ✓
1→21\to2 2e2^{\text{e}} 3e3^{\text{e}} ✓
2→32\to3 3e3^{\text{e}} 4e4^{\text{e}} ✓
2→42\to4 3e3^{\text{e}} 5e5^{\text{e}} ✓

⚠️ Le tri n'est pas unique : 1,0,2,4,31,0,2,4,3 convient aussi. À l'étape 1, on avait le choix entre 00 et 11 ; à l'étape 4, entre 33 et 44. Un DAG admet en général plusieurs tris, tous également valides.

Étape 3 — ce qui se passe avec l'arc $3\to1$

On ajoute 3→13\to1. Le degré entrant de 11 passe de 00 à 11.

sommet degré entrant
00 0\mathbf{0}
11 11 (à cause de 3→13\to1)
22 22
33 11
44 11

Déroulons Kahn :

étape disponibles on sort résultat
1 {0}\{0\} 00 deg⁡−(2):2→1\deg^-(2):2\to1
2 { }\{\,\} — BLOCAGE

Aucun sommet de degré entrant nul, et il reste 44 sommets non sortis.

Il n’existe AUCUN tri topologique.\boxed{\text{Il n'existe AUCUN tri topologique.}}

La raison : le graphe contient un circuit,

1→2→3→1.1\to2\to3\to1.

Vérification : les arcs 1→21\to2, 2→32\to3 et 3→13\to1 sont bien tous présents ✓

Un circuit rend l'ordre impossible : 11 devrait précéder 22, qui devrait précéder 33, qui devrait précéder 11. Il faudrait que 11 soit avant lui-même.

Le blocage est un DÉTECTEUR de circuit

C'est la propriété la plus utile de l'algorithme, et il faut la savoir :

Si Kahn sort moins de nn sommets, le graphe contient un circuit — et les sommets restants sont exactement ceux qui y participent ou en dépendent.

L'algorithme ne fait donc pas que trier : il certifie l'acyclicité. C'est le test de circuit le plus employé en pratique, et il coûte O(n+m)O(n+m).

⚠️ Le blocage n'est pas un échec de l'algorithme, c'est sa réponse. Un programme qui « plante » sur un cycle est mal écrit ; le bon comportement est de rendre « pas de tri, voici le circuit ».

Ce que ça sert à faire

Le tri topologique est partout où il y a des dépendances.

domaine sommets arcs ce qu'un circuit signifie
compilation modules « A importe B » dépendance circulaire — refusée
gestion de projet tâches « A avant B » planning impossible (exercice E4)
tableur cellules « A2 utilise B7 » référence circulaire
build system fichiers dépendances cible impossible à construire
cours modules prérequis cursus impossible

Le message « référence circulaire » d'un tableur, c'est exactement ce blocage de Kahn.

⚠️ Et l'ordre importe pour la suite du chapitre : la méthode PERT (exercice E4) commence par un tri topologique, parce que calculer une date au plus tôt suppose que toutes les tâches amont soient déjà datées.

Réponse : 0,1,2,3,40,1,2,3,4 est un tri topologique valide (il en existe d'autres) ; avec l'arc 3→13\to1, l'algorithme se bloque après le seul sommet 00 — le circuit 1→2→3→11\to2\to3\to1 rend tout tri impossible.

Réponse. Tri valide 0,1,2,3,40,1,2,3,4 ; avec 3→13\to1 le cycle 1→2→3→11\to2\to3\to1 rend tout tri impossible. (Recoupement : Kahn renvoie 55 sommets sans arc 3→13\to1, échoue avec ✓)
Faire cet exercice dans l'app →

Algorithme de Dijkstra

CalculDifficulté 3/5

Graphe orienté pondéré : 0→1 (4)0\to1\,(4), 0→2 (1)0\to2\,(1), 2→1 (2)2\to1\,(2), 1→3 (1)1\to3\,(1), 2→3 (5)2\to3\,(5), 3→4 (3)3\to4\,(3). Calculer les distances depuis 00 et le plus court chemin vers 44.

Indices (3)

Dijkstra fixe à chaque étape le sommet non traité de plus petite distance, puis relâche ses arcs.

Initialiser d0=0d_0=0, les autres =+∞=+\infty.

Relâcher u→vu\to v : si du+w<dvd_u+w<d_v, mettre à jour dvd_v et le prédécesseur.

Correction détaillée
L'idée directrice

L'algorithme de Dijkstra calcule les plus courts chemins depuis une source, dans un graphe à poids positifs ou nuls.

Son principe est celui d'une tache d'huile : on connaît d'abord la distance au sommet le plus proche, puis au suivant, et ainsi de suite par distance croissante. À chaque tour, on fige définitivement le sommet non traité de plus petite distance provisoire.

on extrait toujours le sommet de distance provisoire MINIMALE, et sa valeur devient deˊfinitive.\boxed{\text{on extrait toujours le sommet de distance provisoire MINIMALE, et sa valeur devient définitive.}}

⚠️ Cette garantie repose entièrement sur la positivité des poids — c'est ce que montrera l'exercice B6.

Le graphe
0→1 (4),0→2 (1),2→1 (2),1→3 (1),2→3 (5),3→4 (3).0\to1\ (4),\quad 0\to2\ (1),\quad 2\to1\ (2),\quad 1\to3\ (1),\quad 2\to3\ (5),\quad 3\to4\ (3).

Départ : sommet 00. Distances initiales : d(0)=0d(0)=0 et d(v)=+∞d(v)=+\infty ailleurs.

Le déroulé, tour par tour
tour on extrait dd figée on relâche mises à jour
1 0\mathbf{0} 00 0→1 (4)0\to1\,(4) : ∞→4\infty\to4 d(1)=4d(1)=4, père =0=0
0→2 (1)0\to2\,(1) : ∞→1\infty\to1 d(2)=1d(2)=1, père =0=0
2 2\mathbf{2} 11 2→1 (2)2\to1\,(2) : 1+2=3<41+2=3<4 ✓ d(1)=3d(1)=\mathbf{3}, père =2=\mathbf{2}
2→3 (5)2\to3\,(5) : 1+5=6<∞1+5=6<\infty d(3)=6d(3)=6, père =2=2
3 1\mathbf{1} 33 1→3 (1)1\to3\,(1) : 3+1=4<63+1=4<6 ✓ d(3)=4d(3)=\mathbf{4}, père =1=\mathbf{1}
4 3\mathbf{3} 44 3→4 (3)3\to4\,(3) : 4+3=74+3=7 d(4)=7d(4)=7, père =3=3
5 4\mathbf{4} 77 — fini

Ordre d'extraction : 0, 2, 1, 3, 40,\ 2,\ 1,\ 3,\ 4 — par distance croissante 0,1,3,4,70,1,3,4,7, comme le veut l'algorithme.

d(0)=0,d(1)=3,d(2)=1,d(3)=4,d(4)=7\boxed{d(0)=0,\quad d(1)=3,\quad d(2)=1,\quad d(3)=4,\quad d(4)=7}
Les deux relâchements qui comptent

Le mot relâcher désigne le test d(u)+w<d(v)d(u)+w<d(v), qui améliore une estimation. Deux d'entre eux ont vraiment changé le résultat, et il faut les avoir vus :

Tour 2 — le sommet 11. On avait d(1)=4d(1)=4 par l'arc direct 0→10\to1. Le détour 0→2→10\to2\to1 coûte 1+2=3<41+2=3<4 : le détour est plus court que la ligne directe. C'est précisément ce que l'algorithme est fait pour découvrir.

Tour 3 — le sommet 33. On avait d(3)=6d(3)=6 via 2→32\to3. Le chemin ⋯→1→3\dots\to1\to3 coûte 3+1=4<63+1=4<6 : nouvelle amélioration.

Sans ces deux relâchements, on aurait conclu d(4)=6+3=9d(4)=6+3=9 au lieu de 77.

Le chemin optimal

On remonte les pères depuis 44 :

4 ←peˋre 3 ← 1 ← 2 ← 0.4\ \xleftarrow{\text{père}}\ 3\ \xleftarrow{}\ 1\ \xleftarrow{}\ 2\ \xleftarrow{}\ 0.
0→2→1→3→4\boxed{0\to2\to1\to3\to4}

Vérification par les poids :

1+2+1+3=7=d(4). ✓1+2+1+3=\mathbf{7}=d(4).\ \checkmark

Comparaison avec l'alternative 0→1→3→40\to1\to3\to4 :  4+1+3=8>7\ 4+1+3=8>7. Et 0→2→3→40\to2\to3\to4 :  1+5+3=9>7\ 1+5+3=9>7. Le chemin trouvé est bien le meilleur des trois.

Pourquoi ça marche, et à quel prix

L'invariant : quand on extrait un sommet uu de distance provisoire minimale, cette valeur est définitive.

Preuve en une phrase : tout autre chemin vers uu passerait par un sommet encore non extrait, donc de distance ≥d(u)\ge d(u) ; comme les poids sont ≥0\ge0, ce chemin ne peut qu'être plus long.

C'est ici, et uniquement ici, que la positivité sert — et c'est ce qui tombe en défaut à l'exercice B6.

complexité
avec tas binaire O((n+m)log⁡n)O\big((n+m)\log n\big)
avec tableau simple O(n2)O(n^2)

Pour un graphe peu dense (m≪n2m\ll n^2), le tas gagne largement ; pour un graphe dense, le tableau suffit.

Réponse : d=(0,3,1,4,7)d=(0,3,1,4,7) ; le plus court chemin vers 44 est 0→2→1→3→40\to2\to1\to3\to4, de longueur 77 — et il passe par deux détours, chacun découvert par un relâchement.

Réponse. Distances (0,3,1,4,7)(0,3,1,4,7) ; chemin 0→2→1→3→40\to2\to1\to3\to4 de coût 77. (Recoupement scipy dijkstra : [0,3,1,4,7][0,3,1,4,7] ✓)
Faire cet exercice dans l'app →

Bellman-Ford & poids négatifs

CalculDifficulté 3/5

Graphe orienté 0→1 (4)0\to1\,(4), 0→2 (2)0\to2\,(2), 1→2 (−3)1\to2\,(-3), 2→3 (2)2\to3\,(2). Calculer les plus courtes distances depuis 00 par Bellman-Ford et commenter le rôle de l'arc négatif.

Indices (3)

Dijkstra est exclu : il y a un poids négatif.

Bellman-Ford relâche toutes les arêtes ∣V∣−1=3\lvert V\rvert-1=3 fois.

Comparer le chemin 0→20\to2 direct et 0→1→20\to1\to2.

Correction détaillée
Pourquoi un autre algorithme

Dijkstra exige des poids positifs ou nuls. Dès qu'un arc est négatif, il peut se tromper (exercice B6). Bellman–Ford n'a pas cette limite : il accepte les poids négatifs, au prix d'une méthode plus lente mais plus robuste.

Son principe est brutal et sûr : au lieu de choisir soigneusement quel sommet traiter, on relâche TOUS les arcs, n−1n-1 fois de suite.

pour k=1…n−1:pour chaque arc (u,v,w):d(v)←min⁡(d(v), d(u)+w).\text{pour }k=1\dots n-1 : \quad\text{pour chaque arc }(u,v,w) : \quad d(v)\leftarrow\min\big(d(v),\ d(u)+w\big).
Le graphe
0→1 (4),0→2 (2),1→2 (−3),2→3 (2).0\to1\ (4),\qquad 0\to2\ (2),\qquad 1\to2\ (\mathbf{-3}),\qquad 2\to3\ (2).

L'arc 1→21\to2 a un poids négatif : c'est lui qui rend Dijkstra inutilisable.

Le déroulé

Initialisation : d(0)=0d(0)=0, tout le reste à +∞+\infty. Il y a n=4n=4 sommets, donc n−1=3n-1=3 passes.

après d(0)d(0) d(1)d(1) d(2)d(2) d(3)d(3)
init 00 ∞\infty ∞\infty ∞\infty
passe 1 00 44 1\mathbf{1} 3\mathbf{3}
passe 2 00 44 11 33
passe 3 00 44 11 33
d(0)=0,d(1)=4,d(2)=1,d(3)=3\boxed{d(0)=0,\quad d(1)=4,\quad d(2)=1,\quad d(3)=3}

Détail de la passe 1, en traitant les arcs dans l'ordre donné :

  • 0→1 (4)0\to1\,(4) : d(1)=0+4=4d(1)=0+4=4 ;
  • 0→2 (2)0\to2\,(2) : d(2)=0+2=2d(2)=0+2=2 ;
  • 1→2 (−3)1\to2\,(-3) : 4+(−3)=1<24+(-3)=1<2 ✓ ⇒d(2)=1\Rightarrow d(2)=\mathbf{1} ;
  • 2→3 (2)2\to3\,(2) : 1+2=31+2=3 ⇒d(3)=3\Rightarrow d(3)=3.

Ici tout converge dès la première passe, parce que l'ordre des arcs suit le sens du graphe. Avec un ordre défavorable, il aurait fallu les trois passes — c'est pourquoi l'algorithme les fait toutes.

Le rôle de l'arc négatif

C'est le cœur de l'exercice.

Vers le sommet 22, il y a deux chemins :

chemin coût
0→20\to2 (direct) 22
0→1→20\to1\to2 (détour) 4+(−3)=14+(-3)=\mathbf{1}

Le détour est MOINS cher que la route directe — c'est exactement ce que permet un poids négatif, et c'est ce qui ruine l'intuition géométrique. On ne peut plus se dire « s'éloigner coûte », puisqu'un arc peut rapporter.

Et l'effet se propage : d(3)d(3) passe de 2+2=42+2=4 à 1+2=31+2=\mathbf{3}. Un seul arc négatif améliore toute une branche en aval.

Pourquoi $n-1$ passes suffisent

Un plus court chemin sans circuit a au plus n−1n-1 arcs (il ne repasse par aucun sommet, donc en visite au plus nn).

Or chaque passe garantit au moins un arc de plus dans les chemins correctement calculés : après la passe kk, tous les plus courts chemins d'au plus kk arcs sont exacts.

Après n−1n-1 passes, tous les plus courts chemins sont donc trouvés.

⚠️ Et une nn-ième passe sert de test. Si elle améliore encore quelque chose, c'est qu'il existe un chemin de nn arcs ou plus qui gagne — donc qu'il repasse par un sommet, donc qu'il y a un circuit de poids négatif. C'est l'objet de l'exercice B5.

Ici, la passe supplémentaire n'améliore rien : pas de circuit négatif ✓

Bellman–Ford contre Dijkstra
Dijkstra Bellman–Ford
poids négatifs non oui
circuits négatifs — les détecte
complexité O((n+m)log⁡n)O\big((n+m)\log n\big) O(n m)O(n\,m)
stratégie choisir le meilleur sommet relâcher tout, plusieurs fois
parallélisable difficilement facilement (les relâchements d'une même passe sont indépendants)

Bellman–Ford est nettement plus lent — quadratique au lieu de quasi-linéaire — mais il ne demande aucune hypothèse et il détecte les circuits négatifs. On l'emploie exactement quand Dijkstra ne s'applique pas.

Application réelle : le protocole de routage RIP en réseau est un Bellman–Ford distribué, chaque routeur relâchant les arcs qu'il connaît.

Réponse : d=(0,4,1,3)d=(0,4,1,3) ; l'arc négatif 1→2 (−3)1\to2\,(-3) rend le détour 0→1→20\to1\to2 moins cher (11) que la route directe (22), et cette amélioration se propage jusqu'à 33.

Réponse. Distances (0,4,1,3)(0,4,1,3) ; le chemin 0→1→20\to1\to2 (=1=1) bat 0→20\to2 (=2=2) grâce à l'arc −3-3. (Recoupement scipy bellman_ford : [0,4,1,3][0,4,1,3] ✓)
Faire cet exercice dans l'app →

Floyd-Warshall (toutes paires)

CalculDifficulté 3/5

Sur le graphe de l'exercice B1, on veut les plus courtes distances entre toutes les paires. Quel algorithme et quelle est la distance de 22 à 44 ?

Indices (3)

Floyd-Warshall calcule toutes les paires en O(∣V∣3)O(\lvert V\rvert^3) par programmation dynamique sur les sommets intermédiaires.

Pour d(2,4)d(2,4) : chercher le meilleur trajet de 22 à 44.

Les arcs utiles : 2→1 (2)2\to1\,(2), 1→3 (1)1\to3\,(1), 3→4 (3)3\to4\,(3).

Correction détaillée
La question posée

Dijkstra et Bellman–Ford calculent les distances depuis une source. Si l'on veut toutes les paires (i,j)(i,j), on pourrait relancer Dijkstra nn fois — mais il existe mieux : Floyd–Warshall, qui traite le problème d'un bloc.

Floyd–Warshall : toutes les paires, O(n3), en trois boucles imbriqueˊes.\boxed{\text{Floyd–Warshall : toutes les paires, }O(n^3)\text{, en trois boucles imbriquées.}}
Le principe

L'algorithme repose sur une idée de programmation dynamique remarquablement simple :

Dk[i][j]D_k[i][j] = plus courte distance de ii à jj en n'utilisant comme sommets intermédiaires que 0,1,…,k0,1,\dots,k.

La récurrence s'écrit alors : pour aller de ii à jj en s'autorisant le sommet kk, ou bien on ne passe pas par kk, ou bien on y passe :

Dk[i][j]=min⁡(Dk−1[i][j]⏟sans k, Dk−1[i][k]+Dk−1[k][j]⏟en passant par k).D_k[i][j]=\min\Big(\underbrace{D_{k-1}[i][j]}_{\text{sans }k},\ \underbrace{D_{k-1}[i][k]+D_{k-1}[k][j]}_{\text{en passant par }k}\Big).

D'où le code, qui tient en trois lignes :

pour k, pour i, pour j:D[i][j]←min⁡(D[i][j], D[i][k]+D[k][j]).\textbf{pour }k,\ \textbf{pour }i,\ \textbf{pour }j:\qquad D[i][j]\leftarrow\min\big(D[i][j],\ D[i][k]+D[k][j]\big).

⚠️ L'ordre des boucles n'est pas négociable : kk à l'EXTÉRIEUR. Mettre kk à l'intérieur casse la récurrence — on utiliserait des valeurs pas encore calculées pour le bon ensemble de sommets intermédiaires.

Le résultat sur le graphe de B1
0→1 (4), 0→2 (1), 2→1 (2), 1→3 (1), 2→3 (5), 3→4 (3).0\to1\,(4),\ 0\to2\,(1),\ 2\to1\,(2),\ 1\to3\,(1),\ 2\to3\,(5),\ 3\to4\,(3).

Matrice finale des distances (ligne = départ, colonne = arrivée) :

de \ vers 00 11 22 33 44
0\mathbf{0} 00 33 11 44 77
1\mathbf{1} ∞\infty 00 ∞\infty 11 44
2\mathbf{2} ∞\infty 22 00 33 6\mathbf{6}
3\mathbf{3} ∞\infty ∞\infty ∞\infty 00 33
4\mathbf{4} ∞\infty ∞\infty ∞\infty ∞\infty 00
d(2,4)=6\boxed{d(2,4)=6}

Vérification à la main : de 22 à 44, les chemins possibles sont

chemin coût
2→1→3→42\to1\to3\to4 2+1+3=62+1+3=\mathbf{6}
2→3→42\to3\to4 5+3=85+3=8

Le minimum est bien 66 ✓

Lire la matrice

Trois observations, toutes instructives :

(a) La première ligne est le résultat de Dijkstra de l'exercice B1 : (0,3,1,4,7)(0,3,1,4,7) ✓ Floyd–Warshall contient donc ce calcul, et les n−1n-1 autres.

(b) Beaucoup de ∞\infty, et c'est normal. Le graphe est orienté : de 11, on ne peut jamais revenir vers 00 ni vers 22, car aucun arc ne remonte. La matrice n'est donc pas symétrique — elle le serait sur un graphe non orienté.

(c) La diagonale est nulle : d(i,i)=0d(i,i)=0, on ne bouge pas. (Une valeur négative sur la diagonale signalerait un circuit de poids négatif — c'est le test de détection de Floyd–Warshall, à rapprocher de l'exercice B5.)

Quel algorithme choisir
situation algorithme coût
une source, poids ≥0\ge0 Dijkstra O((n+m)log⁡n)O\big((n+m)\log n\big)
une source, poids quelconques Bellman–Ford O(nm)O(nm)
toutes les paires, graphe dense Floyd–Warshall O(n3)O(n^3)
toutes les paires, graphe creux, poids ≥0\ge0 n×n\times Dijkstra O(n(n+m)log⁡n)O\big(n(n+m)\log n\big)

Le point de bascule. Sur un graphe dense (m≈n2m\approx n^2), nn Dijkstra coûtent O(n3log⁡n)O(n^3\log n) — donc plus que Floyd–Warshall. Sur un graphe creux (m≈nm\approx n), ils coûtent O(n2log⁡n)O(n^2\log n) — donc moins.

Ici : n=5n=5, m=6m=6, graphe creux. Cinq Dijkstra seraient plus rapides — mais Floyd–Warshall tient en trois lignes de code et accepte les poids négatifs, ce que Dijkstra ne fait pas. À cette taille, la simplicité l'emporte.

Sa vraie force : Floyd–Warshall se transpose à d'autres « min-plus », comme la fermeture transitive (existe-t-il un chemin ?) en remplaçant min⁡\min par « ou » et ++ par « et ».

Réponse : Floyd–Warshall, en O(n3)O(n^3) ; la distance de 22 à 44 vaut 6\mathbf6, par le chemin 2→1→3→42\to1\to3\to4 (2+1+32+1+3), meilleur que 2→3→42\to3\to4 qui coûte 88.

Réponse. Floyd-Warshall (O(∣V∣3)O(\lvert V\rvert^3), toutes paires) ; d(2,4)=6d(2,4)=6 via 2→1→3→42\to1\to3\to4. (Recoupement scipy floyd_warshall : d(2,4)=6d(2,4)=6, ligne 0=[0,3,1,4,7]0=[0,3,1,4,7] ✓)
Faire cet exercice dans l'app →

Reconstruction du chemin

ApplicationDifficulté 3/5

On a exécuté Dijkstra depuis 00 sur le graphe de B1 et stocké les prédécesseurs. Comment reconstruire le chemin optimal vers 44 ?

Indices (3)

Le tableau des prédécesseurs donne, pour chaque sommet, par où on l'a atteint au mieux.

Partir de la destination et remonter de prédécesseur en prédécesseur.

Inverser la liste obtenue.

Correction détaillée
Le problème

Dijkstra rend les distances. Mais en pratique on veut le chemin : quel itinéraire suivre ? Le stocker en entier pour chaque sommet coûterait O(n2)O(n^2) en mémoire.

La solution tient en un seul tableau : pour chaque sommet vv, on retient son prédécesseur sur le plus court chemin depuis la source — un seul numéro par sommet, donc O(n)O(n) en mémoire.

Le tableau des prédécesseurs

Sur le graphe de l'exercice B1, Dijkstra a produit :

sommet vv d(v)d(v) père(v)(v) posé au tour
00 00 aucun (source) —
11 33 2\mathbf{2} tour 2
22 11 00 tour 1
33 44 1\mathbf{1} tour 3
44 77 33 tour 4

Le père se met à jour EN MÊME TEMPS que la distance. Quand le relâchement d(u)+w<d(v)d(u)+w<d(v) réussit, on écrit à la fois d(v)←d(u)+wd(v)\leftarrow d(u)+w et père(v)←u(v)\leftarrow u.

⚠️ Noter que père(1)(1) vaut 22 et non 00 : au tour 2, le détour 0→2→10\to2\to1 a battu l'arc direct. Le père enregistre le dernier vainqueur, pas le premier venu.

La reconstruction

On part de la cible et on remonte les pères jusqu'à la source, puis on retourne la liste.

étape sommet courant son père chemin accumulé
1 44 33 [4][4]
2 33 11 [4,3][4,3]
3 11 22 [4,3,1][4,3,1]
4 22 00 [4,3,1,2][4,3,1,2]
5 00 aucun [4,3,1,2,0][4,3,1,2,0] — stop

On retourne :

0→2→1→3→4\boxed{0\to2\to1\to3\to4}

Vérification par les poids : 1+2+1+3=7=d(4)1+2+1+3=7=d(4) ✓

L'algorithme en pseudo-code :

ch←[t] ;tant que peˋre(ch[−1]) existe:ch.ajouter(peˋre(ch[−1])) ;renverser(ch).\texttt{ch}\leftarrow[t]\ ;\quad\textbf{tant que}\ \text{père}(\texttt{ch}[-1])\ \text{existe} : \texttt{ch}.\text{ajouter}(\text{père}(\texttt{ch}[-1]))\ ;\quad\textbf{renverser}(\texttt{ch}).
Les trois contrôles à faire

(a) La somme des poids doit valoir la distance. C'est le contrôle décisif : 1+2+1+3=7=d(4)1+2+1+3=7=d(4) ✓ S'il échoue, le tableau des pères est incohérent avec les distances.

(b) Chaque arc du chemin doit exister. 0→20\to2 ✓, 2→12\to1 ✓, 1→31\to3 ✓, 3→43\to4 ✓ — les quatre sont dans la liste des arcs.

(c) On doit atteindre la source. Si la remontée boucle ou s'arrête ailleurs, il y a une erreur.

⚠️ Le cas où il n'y a pas de chemin : si d(t)=+∞d(t)=+\infty, la cible n'a pas de père, et la reconstruction doit rendre « aucun chemin » — pas une liste vide qu'on lirait comme un chemin de longueur nulle. C'est le cas de 1→01\to0 dans la matrice de l'exercice B3.

Ce que la structure des pères représente

L'ensemble des arcs (peˋre(v),v)\big(\text{père}(v),v\big) forme un arbre couvrant enraciné à la source, appelé arbre des plus courts chemins :

0→2,2→1,1→3,3→4.0\to2,\qquad 2\to1,\qquad 1\to3,\qquad 3\to4.

Quatre arcs pour cinq sommets — c'est bien n−1n-1, comme tout arbre (exercice E3).

Propriété remarquable : ce seul arbre contient les plus courts chemins vers tous les sommets à la fois. Pour aller en 33, on lit 0→2→1→30\to2\to1\to3 ; pour aller en 11, 0→2→10\to2\to1. Un seul tableau de nn entiers encode donc nn itinéraires.

C'est ce qui rend les GPS possibles : on ne stocke pas un chemin par destination, mais un père par carrefour.

⚠️ Ne pas confondre avec l'arbre couvrant MINIMAL des exercices E1–E2 : celui-là minimise le poids total, celui-ci minimise chaque distance à la source. Ce sont deux arbres différents, obtenus par des algorithmes différents.

Réponse : on remonte les pères depuis la cible — 4→3→1→2→04\to3\to1\to2\to0 — puis on retourne, ce qui donne 0→2→1→3→40\to2\to1\to3\to4 ; le contrôle est que la somme des poids, 1+2+1+3=71+2+1+3=7, égale d(4)d(4).

Réponse. Chemin 0→2→1→3→40\to2\to1\to3\to4 obtenu en remontant les prédécesseurs. (Recoupement scipy (return_predecessors) : [0,2,1,3,4][0,2,1,3,4] ✓)
Faire cet exercice dans l'app →

Détection d'un cycle négatif

DémonstrationDifficulté 3/5

Soit le graphe orienté 0→1 (1)0\to1\,(1), 1→2 (1)1\to2\,(1), 2→1 (−3)2\to1\,(-3). Que vaut le plus court chemin de 00 vers 22 ? Qu'en dit Bellman-Ford ?

Indices (3)

Repérer le cycle entre 11 et 22 et calculer son poids total.

Si on peut tourner indéfiniment en diminuant le coût, la notion de plus court chemin s'effondre.

Bellman-Ford détecte une amélioration au ∣V∣\lvert V\rvert-ième tour.

Correction détaillée
Le graphe et le piège
0→1 (1),1→2 (1),2→1 (−3).0\to1\ (1),\qquad 1\to2\ (1),\qquad 2\to1\ (\mathbf{-3}).

Question : que vaut le plus court chemin de 00 vers 22 ?

Réflexe naturel : 0→1→20\to1\to2 coûte 1+1=21+1=2. Mais ce n'est pas la réponse, et il faut regarder ce que le graphe permet de faire.

Le circuit, et ce qu'il coûte

Repérons le circuit :

1→2→1,de poids1+(−3)=−2.1\to2\to1,\qquad\text{de poids}\qquad 1+(-3)=\boxed{-2}.

Ce circuit fait GAGNER 22 à chaque tour. On peut donc l'emprunter autant de fois qu'on veut :

chemin coût
0→1→20\to1\to2 1+1=21+1=2
0→1→2→1→20\to1\to2\to1\to2 2+(−3)+1=02+(-3)+1=0
0→1→2→1→2→1→20\to1\to2\to1\to2\to1\to2 0−3+1=−20-3+1=-2
… kk tours de plus 2−2k2-2k
lim⁡k→∞(2−2k)=−∞.\lim_{k\to\infty}(2-2k)=-\infty.
Il n’existe AUCUN plus court chemin de 0 vers 2:la borne infeˊrieure est −∞.\boxed{\text{Il n'existe AUCUN plus court chemin de }0\text{ vers }2 : \text{la borne inférieure est }-\infty.}

⚠️ Ce n'est pas « la réponse est −∞-\infty » au sens d'une valeur : c'est qu'il n'y a pas de minimum. Quel que soit le chemin proposé, on peut en exhiber un strictement plus court.

Ce qu'en dit Bellman–Ford

L'algorithme fait n−1=2n-1=2 passes, puis une passe supplémentaire de contrôle.

après d(0)d(0) d(1)d(1) d(2)d(2)
init 00 ∞\infty ∞\infty
passe 1 00 −1\mathbf{-1} 22
passe 2 00 −3\mathbf{-3} 0\mathbf{0}
passe 3 (test) 00 −5\mathbf{-5} −2\mathbf{-2}

(arcs traités dans l'ordre 0→10\to1, 1→21\to2, 2→12\to1 ; dès la première passe, le retour 2→12\to1 fait déjà descendre d(1)d(1) à −1-1.)

La passe de contrôle AMÉLIORE encore des distances. C'est exactement le signal :

Si la n-ieˋme passe ameˊliore quelque chose, il y a un circuit de poids neˊgatif.\boxed{\text{Si la }n\text{-ième passe améliore quelque chose, il y a un circuit de poids négatif.}}

Pourquoi c'est un critère sûr. Un plus court chemin sans circuit a au plus n−1n-1 arcs (exercice B2). Après n−1n-1 passes, tous les chemins sans circuit sont donc exacts. Une amélioration supplémentaire ne peut venir que d'un chemin avec circuit — donc d'un circuit qui fait baisser le coût, donc négatif.

Bellman–Ford ne rend pas un résultat faux : il rend un diagnostic. C'est un comportement bien plus utile qu'une valeur arbitraire.

Ce qui a du sens malgré tout

Le circuit négatif ne rend pas tout impossible — il faut savoir ce qui survit.

question réponse
plus court chemin de 00 à 22 n'existe pas (−∞-\infty)
plus court chemin élémentaire (sans répéter de sommet) existe : 0→1→20\to1\to2, de coût 22
existe-t-il un chemin de 00 à 22 ? oui — la connexité est intacte

⚠️ Mais chercher le plus court chemin ÉLÉMENTAIRE en présence de poids négatifs est NP-difficile. Le problème « facile » devient donc « très dur » dès qu'on impose la non-répétition. C'est l'une des bascules les plus nettes du chapitre, à rapprocher de l'exercice D6.

C'est pourquoi les algorithmes de plus court chemin exigent l'absence de circuit négatif : sans cette hypothèse, le problème change de nature.

Où ça arrive en vrai

Un circuit négatif n'est pas une curiosité d'exercice.

domaine ce que serait un circuit négatif
arbitrage de devises une suite de conversions qui crée de l'argent
comptabilité une chaîne d'écritures qui se solde par un gain
ordonnancement des contraintes de dates contradictoires
flots à coût minimal un cycle qu'il faut annuler pour optimiser

L'arbitrage est l'exemple le plus parlant. En posant w=−log⁡(taux)w=-\log(\text{taux}), un circuit de poids négatif correspond à un produit de taux >1>1 : convertir euro → dollar → yen → euro rapporterait plus qu'on n'a mis. Détecter un tel circuit par Bellman–Ford est un algorithme réellement employé en finance — et les marchés efficients les font disparaître en quelques millisecondes.

Cas particulier : un circuit de poids exactement nul ne pose aucun problème. Ce n'est pas la présence d'un circuit qui gêne, c'est son signe.

Réponse : le circuit 1→2→11\to2\to1 pèse −2-2, donc on peut descendre aussi bas qu'on veut — il n'y a pas de plus court chemin de 00 à 22 ; Bellman–Ford le détecte parce que sa nn-ième passe améliore encore les distances.

Réponse. Cycle 1→2→11\to2\to1 de poids −2<0-2<0 : pas de plus court chemin (−∞-\infty), détecté par Bellman-Ford. (Recoupement scipy : NegativeCycleError levée ✓)
Faire cet exercice dans l'app →

Pourquoi Dijkstra échoue en négatif

DémonstrationDifficulté 3/5

Expliquer pourquoi l'algorithme de Dijkstra peut donner un résultat faux sur un graphe à arcs de poids négatif.

Indices (3)

Dijkstra « fixe » définitivement un sommet dès qu'il a la plus petite distance provisoire.

Cette décision suppose qu'aucun chemin futur ne pourra faire mieux.

Un arc négatif viole cette hypothèse.

Correction détaillée
Ce qu'il faut expliquer

Pourquoi Dijkstra peut-il rendre un résultat faux sur un graphe à arcs négatifs ?

La réponse tient à l'invariant qui fonde l'algorithme (exercice B1) :

quand on extrait le sommet de distance provisoire minimale, cette distance est définitive.

Cet invariant repose entièrement sur une hypothèse : s'éloigner coûte. Un arc négatif la détruit.

L'argument, et l'endroit exact où il casse

Preuve de l'invariant, quand les poids sont ≥0\ge0. Soit uu le sommet extrait, de distance provisoire d(u)d(u) minimale. Tout autre chemin vers uu devrait passer par un sommet xx encore non extrait, donc de distance d(x)≥d(u)d(x)\ge d(u). Ce chemin coûterait donc

d(x)+(reste du chemin)⏟≥0 ≥ d(x) ≥ d(u).d(x)+\underbrace{(\text{reste du chemin})}_{\ge0}\ \ge\ d(x)\ \ge\ d(u).

Il ne peut pas faire mieux. ■\blacksquare

L'étape marquée ≥0\ge0 est la seule qui utilise l'hypothèse — et c'est celle qui tombe. Avec des arcs négatifs, le reste du chemin peut être négatif, et un détour par un sommet plus lointain peut finir moins cher.

Le contre-exemple, en chiffres

Reprenons le graphe de l'exercice B2 :

0→1 (4),0→2 (2),1→2 (−3),2→3 (2).0\to1\ (4),\qquad 0\to2\ (2),\qquad 1\to2\ (\mathbf{-3}),\qquad 2\to3\ (2).

Déroulons Dijkstra :

tour on extrait dd figée on relâche
1 00 00 d(1)=4d(1)=4, d(2)=2d(2)=2
2 2\mathbf{2} 2\mathbf{2} — FIGÉE d(3)=2+2=4d(3)=2+2=\mathbf{4}
3 11 44 1→21\to2 : 4−3=1<24-3=1<2… mais 22 est déjà extrait
4 33 44 —

Le résultat de Dijkstra : d(3)=4d(3)=4.

La vérité, par Bellman–Ford (exercice B2) : d(3)=3d(3)=\mathbf{3}, par le chemin 0→1→2→30\to1\to2\to3 de coût 4−3+2=34-3+2=3.

Dijkstra se trompe sur le sommet 3:il rend 4 au lieu de 3.\boxed{\text{Dijkstra se trompe sur le sommet }3 : \text{il rend }4\text{ au lieu de }3.}
Le mécanisme précis de l'erreur

Au tour 2, Dijkstra extrait le sommet 22 avec d(2)=2d(2)=2 et fige cette valeur. Il en déduit aussitôt d(3)=4d(3)=4.

Au tour 3, il découvre que 22 était en fait à distance 11 (via le détour par 11). Mais il est trop tard :

  • le sommet 22 est déjà extrait, donc l'algorithme ne le retraite pas ;
  • ses successeurs — ici 33 — ne sont donc jamais recalculés ;
  • l'erreur de 11 sur d(2)d(2) se propage en une erreur de 11 sur d(3)d(3).

⚠️ Le sommet 22 lui-même finit avec la bonne valeur dans certaines implémentations (celles qui écrivent d(2)=1d(2)=1 même après extraction). C'est trompeur : la valeur affichée est juste, mais elle n'a pas été propagée. L'erreur ne se voit que sur le sommet 33, en aval.

Leçon de méthode : vérifier un algorithme sur la seule valeur qu'on regarde ne suffit pas. Ici d(2)d(2) est correct et d(3)d(3) ne l'est pas.

Ce qu'il ne faut PAS essayer

Deux « réparations » viennent naturellement à l'esprit. Les deux échouent, et savoir pourquoi vaut mieux que de les essayer.

(a) « Ajouter une constante à tous les poids pour les rendre positifs. » Cela change le problème : un chemin de kk arcs voit son coût augmenter de k×Ck\times C. Les chemins longs sont donc pénalisés davantage que les courts, et le plus court chemin peut changer.

Sur notre exemple avec C=3C=3 : 0→2→30\to2\to3 coûterait 5+5=105+5=10, et 0→1→2→30\to1\to2\to3 coûterait 7+0+5=127+0+5=12. On conclurait au premier, alors que le vrai optimum est le second.

(b) « Autoriser la réextraction d'un sommet déjà figé. » L'algorithme devient correct (en l'absence de circuit négatif)… mais sa complexité explose — il peut extraire un sommet un nombre exponentiel de fois. On a alors réinventé, en moins bien, ce que Bellman–Ford fait proprement.

La seule bonne réponse est de changer d'algorithme.

poids algorithme
tous ≥0\ge0 Dijkstra, O((n+m)log⁡n)O\big((n+m)\log n\big)
quelconques, sans circuit négatif Bellman–Ford, O(nm)O(nm)
graphe acyclique, poids quelconques tri topologique + relâchement, O(n+m)O(n+m)

La troisième ligne est utile : sur un DAG (exercice A6), les poids négatifs ne posent aucun problème, et l'on est même plus rapide que Dijkstra.

Réponse : Dijkstra fige la distance d'un sommet à son extraction, ce qui n'est justifié que si les poids sont ≥0\ge0 ; sur 0→1 (4)0\to1\,(4), 0→2 (2)0\to2\,(2), 1→2 (−3)1\to2\,(-3), 2→3 (2)2\to3\,(2), il fige d(2)=2d(2)=2 trop tôt et rend d(3)=4d(3)=4 au lieu de 33.

Réponse. L'hypothèse gloutonne « un sommet fixé ne s'améliore plus » tombe avec un arc négatif ⇒\Rightarrow utiliser Bellman-Ford. (Recoupement : cf. B2, où le détour négatif bat l'arc direct ✓)
Faire cet exercice dans l'app →

Arbre couvrant minimal (Kruskal)

CalculDifficulté 3/5

Graphe non orienté pondéré, arêtes (poids) : 01 (2)01\,(2), 03 (6)03\,(6), 12 (3)12\,(3), 13 (8)13\,(8), 14 (5)14\,(5), 24 (7)24\,(7), 34 (9)34\,(9). Trouver l'arbre couvrant minimal par Kruskal.

Indices (3)

Trier les arêtes par poids croissant.

Ajouter chaque arête si elle ne crée pas de cycle (union-find).

S'arrêter à ∣V∣−1=4\lvert V\rvert-1=4 arêtes.

Correction détaillée
L'idée directrice

Un arbre couvrant minimal (ACM) est un sous-graphe qui relie tous les sommets avec le poids total le plus petit possible, et sans cycle.

C'est le problème du câblage : relier nn villes par des routes, au coût minimal.

L'algorithme de Kruskal procède par arêtes, dans l'ordre croissant des poids :

on trie les arêtes par poids croissant, et on prend chacune sauf si elle crée un cycle.

C'est un algorithme glouton — il ne revient jamais sur ses choix — et, fait remarquable, il donne l'optimum exact.

Étape 1 — trier les arêtes

Arêtes et poids : 01 (2)01\,(2), 03 (6)03\,(6), 12 (3)12\,(3), 13 (8)13\,(8), 14 (5)14\,(5), 24 (7)24\,(7), 34 (9)34\,(9).

Triées par poids croissant :

01 (2),12 (3),14 (5),03 (6),24 (7),13 (8),34 (9).01\,(2),\quad 12\,(3),\quad 14\,(5),\quad 03\,(6),\quad 24\,(7),\quad 13\,(8),\quad 34\,(9).
Étape 2 — parcourir et décider
arête poids crée un cycle ? décision composantes après
0101 22 non PRISE {0,1}\{0,1\}, {2}\{2\}, {3}\{3\}, {4}\{4\}
1212 33 non PRISE {0,1,2}\{0,1,2\}, {3}\{3\}, {4}\{4\}
1414 55 non PRISE {0,1,2,4}\{0,1,2,4\}, {3}\{3\}
0303 66 non PRISE {0,1,2,3,4}\{0,1,2,3,4\} — tout relié
2424 77 oui (22 et 44 déjà reliés) rejetée —
1313 88 oui rejetée —
3434 99 oui rejetée —
ACM={01, 12, 14, 03},poids=2+3+5+6=16\boxed{\text{ACM} = \{01,\ 12,\ 14,\ 03\},\qquad \text{poids} = 2+3+5+6 = \mathbf{16}}

Contrôles :

  • 44 arêtes pour 55 sommets, soit n−1n-1 ✓ (exercice E3) ;
  • une seule composante à la fin ✓ ;
  • on s'arrête dès qu'on a n−1n-1 arêtes : les trois dernières n'ont même pas besoin d'être examinées.
Le test « crée un cycle ? »

C'est l'opération critique de l'algorithme, et sa mise en œuvre décide de la complexité.

Une arête uvuv crée un cycle si et seulement si uu et vv sont déjà dans la même composante.

Vérifions sur 24 (7)24\,(7) : après les trois premières arêtes, la composante contient {0,1,2,4}\{0,1,2,4\}. Les sommets 22 et 44 y sont tous deux ⟹\Longrightarrow il existe déjà un chemin entre eux (2→1→42\to1\to4), donc l'arête 2424 fermerait un cycle ✓

La structure adaptée est l'union–find (union par rang, compression de chemin), qui répond en temps quasi constant :

O(mlog⁡m) pour le tri + O(m α(n)) pour les tests ≈ O(mlog⁡m).O(m\log m)\ \text{pour le tri}\ +\ O(m\,\alpha(n))\ \text{pour les tests}\ \approx\ O(m\log m).

Le tri domine — c'est lui qui fixe la complexité.

Pourquoi le glouton donne l'OPTIMUM

C'est le point qui mérite explication : un algorithme glouton donne rarement l'optimum, ici toujours.

Propriété de la coupe. Soit une partition des sommets en deux groupes. L'arête de poids minimal qui les traverse appartient à un ACM.

Démonstration par échange : si un ACM ne la contenait pas, lui ajouter ee créerait un cycle, qui traverse la partition une seconde fois par une arête e′e', de poids ≥\ge. En remplaçant e′e' par ee, on obtient encore un arbre couvrant, de poids ≤\le. Donc ee est dans un ACM.

Kruskal ne fait rien d'autre qu'appliquer cette propriété à répétition : chaque arête prise est la plus légère qui relie deux composantes encore séparées.

⚠️ Cette propriété est propre aux arbres couvrants. Le même raisonnement glouton sur le voyageur de commerce (exercice D2) ou le sac à dos (D1) échoue — c'est ce qui sépare les problèmes faciles des problèmes NP-difficiles.

Réponse : ACM ={01,12,14,03}=\{01,12,14,03\}, de poids 16\mathbf{16} ; les arêtes 2424, 1313 et 3434 sont rejetées car elles fermeraient un cycle.

Réponse. ACM de poids 1616 (arêtes 01,12,14,0301,12,14,03). (Recoupement : Prim donne 1616, et scipy minimum_spanning_tree somme 1616 ✓)
Faire cet exercice dans l'app →

Prim vs Kruskal

DémonstrationDifficulté 3/5

Sur le graphe de E1, exécuter Prim depuis le sommet 00 et vérifier qu'on retrouve le même poids qu'avec Kruskal.

Indices (3)

Prim fait croître un arbre depuis un sommet de départ.

À chaque étape, ajouter l'arête la moins chère sortant de l'arbre courant.

Continuer jusqu'à couvrir tous les sommets.

Correction détaillée
L'autre stratégie

Kruskal (exercice E1) raisonne par arêtes, en partant du graphe entier. Prim raisonne par sommets, en partant d'un seul et en faisant grossir un arbre :

on part d'un sommet, et à chaque tour on ajoute l'arête la plus légère qui sort de l'arbre déjà construit.

C'est la même idée gloutonne, appliquée à une frontière qui avance — très proche de Dijkstra dans sa mécanique (un tas, une extraction du minimum), mais avec un critère différent.

Le déroulé depuis le sommet $0$

Arêtes : 01 (2)01\,(2), 03 (6)03\,(6), 12 (3)12\,(3), 13 (8)13\,(8), 14 (5)14\,(5), 24 (7)24\,(7), 34 (9)34\,(9).

tour arbre courant arêtes sortantes (poids) la plus légère on ajoute
1 {0}\{0\} 01 (2)01\,(2), 03 (6)03\,(6) 01 (2)\mathbf{01\,(2)} sommet 11
2 {0,1}\{0,1\} 03 (6)03\,(6), 12 (3)12\,(3), 13 (8)13\,(8), 14 (5)14\,(5) 12 (3)\mathbf{12\,(3)} sommet 22
3 {0,1,2}\{0,1,2\} 03 (6)03\,(6), 13 (8)13\,(8), 14 (5)14\,(5), 24 (7)24\,(7) 14 (5)\mathbf{14\,(5)} sommet 44
4 {0,1,2,4}\{0,1,2,4\} 03 (6)03\,(6), 13 (8)13\,(8), 34 (9)34\,(9) 03 (6)\mathbf{03\,(6)} sommet 33
5 {0,1,2,3,4}\{0,1,2,3,4\} — — fini
ACM={01, 12, 14, 03},poids=2+3+5+6=16\boxed{\text{ACM} = \{01,\ 12,\ 14,\ 03\},\qquad \text{poids} = 2+3+5+6 = \mathbf{16}}

⚠️ À chaque tour, on ne regarde QUE les arêtes qui sortent de l'arbre. Au tour 3, l'arête 12 (3)12\,(3) n'est plus candidate : ses deux extrémités sont dans l'arbre. La prendre créerait un cycle.

La comparaison avec Kruskal
Kruskal Prim
poids total 16\mathbf{16} 16\mathbf{16}
arêtes 01,12,14,0301,12,14,03 01,12,14,0301,12,14,03
ordre d'ajout 2,3,5,62,3,5,6 (poids croissant global) 2,3,5,62,3,5,6

Même poids ET mêmes arêtes ✓

L'ordre coïncide ici, mais ce n'est pas une règle : Kruskal prend les arêtes par poids croissant dans tout le graphe, Prim par poids croissant au bord de son arbre. Sur un autre graphe, les ordres diffèrent — et les arbres aussi, si plusieurs ACM existent.

Quand les arbres peuvent-ils différer ? Uniquement si le graphe a plusieurs ACM, ce qui suppose des poids égaux. Ici les sept poids sont deux à deux distincts :

2,3,5,6,7,8,9tous distincts ⟹ l’ACM est UNIQUE.2,3,5,6,7,8,9\quad\text{tous distincts}\ \Longrightarrow\ \textbf{l'ACM est UNIQUE.}

C'est un théorème : si tous les poids sont distincts, l'arbre couvrant minimal est unique. Les deux algorithmes devaient donc trouver le même — leur accord n'est pas une chance, c'est une conséquence.

Lequel choisir en pratique
Kruskal Prim (avec tas) Prim (avec tableau)
complexité O(mlog⁡m)O(m\log m) O(mlog⁡n)O\big(m\log n\big) O(n2)O(n^2)
adapté aux graphes creux creux denses
structure union–find tas de priorité tableau
se parallélise plutôt bien mal mal

Le critère est la densité. Sur un graphe creux (m≈nm\approx n), Kruskal est simple et rapide. Sur un graphe dense (m≈n2m\approx n^2), Prim avec tableau tourne en O(n2)O(n^2) alors que le seul tri de Kruskal coûterait O(n2log⁡n)O(n^2\log n).

Prim ressemble beaucoup à Dijkstra (exercice B1) : même boucle, même tas, même extraction du minimum. La seule différence tient au critère — Dijkstra compare d(u)+wd(u)+w (distance depuis la source), Prim compare ww seul (coût de raccordement). Un caractère de code, deux problèmes différents.

Réponse : Prim depuis 00 ajoute 01 (2)01\,(2), 12 (3)12\,(3), 14 (5)14\,(5), 03 (6)03\,(6) — soit le même arbre que Kruskal, de poids 16\mathbf{16} ; c'était garanti, les sept poids étant distincts, l'ACM est unique.

Réponse. Prim depuis 00 : poids 1616, comme Kruskal. (Recoupement : prim=kruskal=16=16 ✓)
Faire cet exercice dans l'app →

Arbre couvrant : nombre d'arêtes

DémonstrationDifficulté 3/5

Pourquoi un arbre couvrant d'un graphe à n=5n=5 sommets a-t-il exactement 44 arêtes ? Que signifierait une cinquième arête ?

Indices (3)

Un arbre est connexe et sans cycle.

Un graphe connexe à nn sommets a au moins n−1n-1 arêtes.

Ajouter une arête à un arbre crée un cycle.

Correction détaillée
Ce qu'il faut démontrer

Pourquoi un arbre couvrant d'un graphe à n=5n=5 sommets a-t-il exactement 44 arêtes ?

La réponse est un théorème de structure, et il tient à la définition même d'un arbre : un graphe connexe et sans cycle.

arbre aˋ n sommets ⟺ n−1 areˆtes, connexe ⟺ n−1 areˆtes, sans cycle\boxed{\text{arbre à }n\text{ sommets}\ \Longleftrightarrow\ n-1\ \text{arêtes, connexe}\ \Longleftrightarrow\ n-1\ \text{arêtes, sans cycle}}

Deux des trois propriétés — connexité, acyclicité, n−1n-1 arêtes — impliquent toujours la troisième. C'est ce qui rend les arbres si commodes.

La démonstration, par construction

Construisons l'arbre en ajoutant les sommets un par un.

Départ : 11 sommet, 00 arête.

À chaque étape, on rattache un nouveau sommet à l'arbre déjà construit. Il faut exactement une arête :

  • moins d'une (c'est-à-dire zéro) : le sommet resterait isolé, le graphe ne serait plus connexe ;
  • plus d'une : le nouveau sommet aurait deux voisins déjà reliés entre eux — cela fermerait un cycle.

Après n−1n-1 étapes, on a nn sommets et n−1n-1 arêtes. ■\blacksquare

Pour n=5n=5 : 44 arêtes ✓ — c'est exactement le compte trouvé aux exercices E1 et E2.

Ce que signifierait une CINQUIÈME arête

Ajoutons une arête à un arbre à 55 sommets et 44 arêtes. Ses deux extrémités sont déjà reliées (l'arbre est connexe), donc il existe déjà un chemin entre elles.

nouveau chemin+ancien chemin = CYCLE.\text{nouveau chemin}+\text{ancien chemin}\ =\ \textbf{CYCLE.}
Toute areˆte ajouteˊe aˋ un arbre creˊe EXACTEMENT un cycle.\boxed{\text{Toute arête ajoutée à un arbre crée EXACTEMENT un cycle.}}

Sur l'exercice E1 : l'ACM est {01,12,14,03}\{01,12,14,03\}. Ajoutons 2424 :

  • ancien chemin de 22 à 44 : 2→1→42\to1\to4 ;
  • avec la nouvelle arête : le cycle 2→1→4→22\to1\to4\to2 ✓

C'est exactement la raison pour laquelle Kruskal l'a rejetée. Le test « crée un cycle ? » et le compte « n−1n-1 arêtes » sont les deux faces du même fait.

Et symétriquement : retirer une arête d'un arbre le déconnecte toujours en deux morceaux, puisqu'aucun chemin de secours n'existe. Un arbre est donc minimalement connexe — on ne peut rien enlever — et maximalement acyclique — on ne peut rien ajouter.

Le tableau des cas

Pour un graphe à nn sommets et mm arêtes :

mm conséquence
m<n−1m<n-1 jamais connexe — au moins n−mn-m composantes
m=n−1m=n-1 arbre si et seulement si connexe (ou, ce qui revient au même, sans cycle)
m>n−1m>n-1 au moins un cycle, quelle que soit la disposition

⚠️ Le cas m=n−1m=n-1 ne suffit pas à conclure. Le graphe de l'exercice A3 a 55 sommets et 44 arêtes — donc m=n−1m=n-1 — et pourtant deux composantes : le triangle {0,1,2}\{0,1,2\} gaspille une arête dans un cycle, et il en manque une pour rejoindre {3,4}\{3,4\}.

Le compte d'arêtes est nécessaire, jamais suffisant. Il faut toujours lui adjoindre la connexité ou l'acyclicité.

Le nombre m−n+1m-n+1 s'appelle le nombre cyclomatique : c'est le nombre de cycles indépendants. Pour un arbre il vaut 00 ; pour le graphe de l'exercice A1 (55 sommets, 55 arêtes) il vaut 11 — il y a bien exactement un cycle, le triangle 0→1→2→00\to1\to2\to0.

Ce que ça sert à faire

Ce compte est un contrôle immédiat de tout résultat du chapitre.

situation contrôle
ACM (E1, E2) doit avoir exactement n−1n-1 arêtes
arbre des plus courts chemins (B4) pareil
parcours BFS/DFS (A2) son arbre a n−1n-1 arêtes
structure de données (arbre binaire) nn nœuds, n−1n-1 liens

Un résultat qui n'a pas n−1n-1 arêtes est faux, sans qu'on ait besoin de vérifier autre chose : trop peu et le graphe est déconnecté, trop et il y a un cycle. C'est le contrôle le moins cher et le plus efficace de tout le lot E.

Conséquence pratique en câblage : relier nn bâtiments coûte au minimum n−1n-1 liaisons. Une nn-ième liaison n'améliore pas la connexité — elle apporte de la redondance, ce qui est un autre objectif (tolérance aux pannes) et se paie en plus.

Réponse : n−1=4n-1=4 arêtes, parce que chaque nouveau sommet demande exactement une arête pour être rattaché sans créer de cycle ; une cinquième arête relierait deux sommets déjà connectés et créerait donc exactement un cycle.

Réponse. n−1=4n-1=4 arêtes (connexe + sans cycle) ; une 5e5^\text{e} arête créerait un cycle. (Recoupement : Kruskal s'arrête à 44 arêtes ✓)
Faire cet exercice dans l'app →

Ordonnancement PERT — durée du projet

ApplicationDifficulté 3/5

Un projet a 55 tâches A,B,C,D,EA,B,C,D,E de durées 3,2,4,1,23,2,4,1,2, avec les dépendances A→CA\to C, B→CB\to C, C→DC\to D, C→EC\to E. Quelle est la durée minimale du projet et le chemin critique ?

Indices (3)

Les dépendances forment un DAG ; on calcule les dates de début au plus tôt.

Date au plus tôt d'une tâche =max⁡=\max des dates de fin de ses prédécesseurs.

La durée du projet est le plus long chemin.

Correction détaillée
La méthode PERT

Un projet est un ensemble de tâches avec des dépendances. La question est : combien de temps au minimum ?

La réponse n'est ni la somme des durées (les tâches indépendantes se font en parallèle) ni la plus longue tâche : c'est la longueur du chemin critique, le plus long chemin de dépendances.

dureˊe minimale=longueur du plus LONG chemin dans le graphe de deˊpendances.\boxed{\text{durée minimale}=\text{longueur du plus LONG chemin dans le graphe de dépendances.}}

⚠️ C'est un plus LONG chemin, pas un plus court — l'inverse des exercices du lot B. Le problème serait NP-difficile en général, mais il est facile sur un DAG (exercice A6) : il suffit de parcourir les tâches dans l'ordre topologique.

Les données
tâche durée dépend de
AA 33 —
BB 22 —
CC 44 AA, BB
DD 11 CC
EE 22 CC

Le graphe : A→CA\to C, B→CB\to C, C→DC\to D, C→EC\to E.

Tri topologique (exercice A6) : A,B,C,D,EA,B,C,D,E — chaque tâche apparaît après toutes celles dont elle dépend ✓ C'est dans cet ordre qu'on va calculer.

Étape 1 — les dates au plus tôt

La date de début au plus tôt d'une tâche est la plus tardive des fins de ses prédécesseurs — il faut que tous soient finis :

deˊbut(t)=max⁡p → t(deˊbut(p)+dureˊe(p)),et 0 s’il n’y a pas de preˊdeˊcesseur.\text{début}(t)=\max_{p\ \to\ t}\big(\text{début}(p)+\text{durée}(p)\big),\qquad\text{et }0\text{ s'il n'y a pas de prédécesseur.}
tâche calcul début fin
AA aucun prédécesseur 00 0+3=30+3=3
BB aucun prédécesseur 00 0+2=20+2=2
CC max⁡(finA,finB)=max⁡(3,2)\max(\text{fin}A,\text{fin}B)=\max(3,2) 3\mathbf{3} 3+4=73+4=7
DD fin C\,C 77 7+1=87+1=8
EE fin C\,C 77 7+2=97+2=\mathbf{9}
DUREˊE MINIMALE=max⁡(fins)=9\boxed{\text{DURÉE MINIMALE}=\max(\text{fins})=\mathbf{9}}

⚠️ Le max⁡\max de la ligne CC est le cœur du calcul. CC ne peut pas démarrer à 22 (fin de BB) : elle doit attendre AA, qui finit à 33. C'est la tâche la plus lente qui commande — pas la moyenne, pas la somme.

Étape 2 — le chemin critique

Énumérons les quatre chemins complets et leurs durées :

chemin durées total
A→C→DA\to C\to D 3+4+13+4+1 88
A→C→E\mathbf{A\to C\to E} 3+4+23+4+2 9\mathbf{9} ← CRITIQUE
B→C→DB\to C\to D 2+4+12+4+1 77
B→C→EB\to C\to E 2+4+22+4+2 88
chemin critique:A→C→E, de dureˊe 9\boxed{\text{chemin critique} : A\to C\to E,\ \text{de durée }9}

Le maximum, 99, coïncide bien avec la durée trouvée à l'étape 1 ✓ — c'est le contrôle qui valide le calcul, par une voie entièrement différente.

Ce que « critique » signifie

Une tâche est critique quand tout retard sur elle retarde tout le projet.

Vérifions sur AA (critique) : si AA prend 44 au lieu de 33, alors CC démarre à 44, finit à 88, EE finit à 1010. Le projet passe de 99 à 1010 — le retard se répercute intégralement.

Vérifions sur BB (non critique) : si BB prend 33 au lieu de 22, elle finit à 33. Mais CC démarrait déjà à 33 à cause de AA : rien ne change, le projet reste à 99.

B dispose d’une MARGE : elle peut glisser sans conseˊquence.\boxed{B\ \text{dispose d'une MARGE}\ :\ \text{elle peut glisser sans conséquence.}}

C'est exactement ce que l'exercice E5 va chiffrer.

Le contraste est frappant : les deux tâches sont des prédécesseurs de CC, mais l'une commande le projet et l'autre non. Ce n'est ni la durée ni la position qui décide, c'est l'appartenance au chemin le plus long.

Pourquoi c'est facile ici, et difficile ailleurs

Chercher un plus long chemin est NP-difficile dans un graphe général — c'est essentiellement le problème du chemin hamiltonien.

Mais sur un DAG, c'est linéaire : sans circuit, on peut trier les sommets topologiquement, et chaque date se calcule une fois pour toutes à partir de celles déjà connues. Coût : O(n+m)O(n+m).

⚠️ D'où l'importance du tri topologique de l'exercice A6 : il n'est pas décoratif, il est ce qui rend PERT calculable. Et si le graphe de dépendances contenait un circuit — « AA avant BB, BB avant CC, CC avant AA » —, il n'y aurait aucun planning possible, et le blocage de Kahn le dirait.

La méthode PERT (Program Evaluation and Review Technique) a été mise au point en 1958 pour le programme de missiles Polaris ; la méthode jumelle CPM (Critical Path Method) l'a été à la même époque (1957) chez DuPont. Toutes deux sont, mathématiquement, ce calcul de plus long chemin sur un DAG.

Réponse : la durée minimale est 9\mathbf{9}, et le chemin critique est A→C→EA\to C\to E (3+4+23+4+2) ; CC ne peut démarrer qu'à la date 33, imposée par AA et non par BB.

Réponse. Durée minimale 99, chemin critique A→C→EA\to C\to E. (Recoupement : dates au plus tôt [0,0,3,7,7][0,0,3,7,7], durée projet 99 ✓)
Faire cet exercice dans l'app →

Marges et tâches critiques

CalculDifficulté 3/5

Pour le projet de E4 (durée 99), calculer la marge de chaque tâche et identifier les tâches critiques.

Indices (3)

Calculer les dates de début au plus tard (rétro-planning depuis la fin 99).

Marge == date au plus tard −- date au plus tôt.

Une tâche est critique si sa marge est nulle.

Correction détaillée
La notion de marge

La marge d'une tâche est le retard qu'elle peut prendre sans retarder le projet. Elle se calcule en confrontant deux dates :

date définition sens du calcul
au plus tôt toˆt(t)\text{tôt}(t) le plus tôt où tt peut commencer en avant, depuis le début
au plus tard tard(t)\text{tard}(t) le plus tard où tt peut commencer sans retarder le projet en arrière, depuis la fin
marge(t)=tard(t)−toˆt(t)\boxed{\text{marge}(t)=\text{tard}(t)-\text{tôt}(t)}

Une tâche de marge nulle est critique : elle n'a aucune souplesse.

Étape 1 — les dates au plus tôt (rappel de E4)
tâche durée tôt fin au plus tôt
AA 33 00 33
BB 22 00 22
CC 44 33 77
DD 11 77 88
EE 22 77 99

Durée du projet : T=9T=9.

Étape 2 — les dates au plus tard, EN REMONTANT

On part de la fin et on remonte. La formule est :

tard(t)=min⁡t → s(tard(s))−dureˊe(t),\text{tard}(t)=\min_{t\ \to\ s}\big(\text{tard}(s)\big)-\text{durée}(t),

et pour une tâche sans successeur, tard(t)=T−dureˊe(t)\text{tard}(t)=T-\text{durée}(t).

⚠️ Attention à la formule : on prend le min des dates de début des successeurs, puis on retranche sa propre durée. L'erreur classique est de retrancher la durée du successeur — ce qui donne un résultat faux.

tâche successeurs calcul tard
EE aucun 9−29-2 7\mathbf{7}
DD aucun 9−19-1 8\mathbf{8}
CC DD, EE min⁡(8,7)−4=7−4\min(8,7)-4=7-4 3\mathbf{3}
BB CC 3−23-2 1\mathbf{1}
AA CC 3−33-3 0\mathbf{0}

Le min⁡\min sur la ligne CC compte : CC doit finir avant que le premier de ses successeurs ne démarre, donc avant 77 (date de EE), et non avant 88.

Étape 3 — les marges
tâche tôt tard marge statut
AA 00 00 0\mathbf{0} CRITIQUE
BB 00 11 11 souple
CC 33 33 0\mathbf{0} CRITIQUE
DD 77 88 11 souple
EE 77 77 0\mathbf{0} CRITIQUE
taˆches critiques:A, C, E\boxed{\text{tâches critiques} : A,\ C,\ E}

Contrôle décisif : ces trois tâches sont exactement le chemin critique A→C→EA\to C\to E trouvé à l'exercice E4 ✓ Les deux méthodes — énumérer les chemins, ou calculer les marges — doivent toujours désigner les mêmes tâches. C'est ce qui valide le calcul.

Vérifier les marges une par une

BB, marge 11. Si BB prend 33 au lieu de 22, elle finit à 33 — et CC démarrait déjà à 33 à cause de AA. Le projet reste à 9\mathbf9 ✓ Mais si BB prenait 44 (retard de 2>12>1), elle finirait à 44, CC démarrerait à 44, et le projet passerait à 1010. La marge est bien de 11, pas plus.

DD, marge 11. DD finit à 88 alors que le projet dure 99 : elle a une unité de battement. Si DD prenait 22 au lieu de 11, elle finirait à 99 — juste à temps.

AA, marge 00. Tout retard sur AA décale CC, donc EE, donc le projet ✓ (vérifié à l'exercice E4 : AA à 44 donne un projet à 1010).

Ces trois vérifications sont la meilleure façon de s'assurer qu'on n'a pas confondu les dates. Une marge qui ne « résiste » pas au test est mal calculée.

Ce que les marges apportent en pratique

Le chemin critique est ce qu'un chef de projet surveille en priorité : c'est la seule chaîne où un jour perdu est un jour perdu pour tout le monde.

marge ce que ça permet
00 rien — surveiller de près
>0>0 absorber un aléa, décaler le démarrage, lisser les ressources

Deux usages concrets de la marge :

  • lissage des ressources. Si BB et AA demandent la même équipe, on peut décaler BB de 11 sans coût. Cela libère la date 00, sans supprimer le chevauchement (il glisse sur [1,3][1,3]) : pour séparer AA et BB, il faudrait décaler BB de 33, au-delà de sa marge.
  • absorption des aléas. Une tâche de marge 22 tolère deux jours de retard imprévu ; une tâche critique, aucun.

⚠️ Le chemin critique BOUGE dès qu'on modifie le projet. Si l'on accélère EE de 22 à 11, alors A→C→EA\to C\to E ne dure plus que 88, et A→C→DA\to C\to D (qui durait 88) devient critique à égalité. Les marges sont donc à recalculer après chaque changement — c'est le sujet de l'exercice E6.

Il existe aussi une marge libre — le retard possible sans décaler la tâche suivante — toujours ≤\le à la marge totale calculée ici. Sur ce projet, BB a une marge totale de 11 et une marge libre de 11 également, puisque son unique successeur CC démarre à 33.

Réponse : marges A=0A=0, B=1B=1, C=0C=0, D=1D=1, E=0E=0 ; les tâches critiques sont AA, CC et EE — exactement le chemin critique de l'exercice E4.

Réponse. Marges (0,1,0,1,0)(0,1,0,1,0) ; tâches critiques A,C,EA,C,E. (Recoupement : pert_tard donne marges [0,1,0,1,0][0,1,0,1,0] ✓)
Faire cet exercice dans l'app →

Piloter le délai d'un projet

DémonstrationDifficulté 3/5

Dans le projet de E4-E5, le chef de projet veut raccourcir la durée totale. Sur quelles tâches doit-il agir, et qu'apporte une accélération de BB ou de DD ?

Indices (3)

Seules les tâches du chemin critique fixent la durée totale.

Accélérer une tâche à marge non nulle ne fait que consommer cette marge.

Le chemin critique est A→C→EA\to C\to E ; BB et DD ont une marge de 11.

Correction détaillée
La question, et la réponse en une ligne

Le chef de projet veut raccourcir la durée totale. Sur quelles tâches agir ?

UNIQUEMENT sur les taˆches CRITIQUES : A, C, E.\boxed{\text{UNIQUEMENT sur les tâches CRITIQUES : }A,\ C,\ E.}

Accélérer une tâche non critique ne sert à RIEN — elle ne fait qu'augmenter sa marge, déjà positive. C'est le résultat le plus contre-intuitif de la gestion de projet, et le plus utile.

La vérification, tâche par tâche

On accélère chaque tâche d'une unité et l'on recalcule la durée du projet (initialement 99) :

on accélère marge nouvelle durée gain
A\mathbf{A} (3→23\to2) 00 8\mathbf{8} −1\mathbf{-1} ✓
C\mathbf{C} (4→34\to3) 00 8\mathbf{8} −1\mathbf{-1} ✓
E\mathbf{E} (2→12\to1) 00 8\mathbf{8} −1\mathbf{-1} ✓
BB (2→12\to1) 11 99 0\mathbf{0} ✗
DD (1→01\to0) 11 99 0\mathbf{0} ✗

Le tableau est sans appel : les trois tâches critiques rapportent chacune une unité, les deux autres rien du tout.

Pourquoi accélérer $B$ ne sert à rien

BB dure 22 et finit à la date 22. Mais CC ne démarre qu'à 33, parce qu'elle attend AA.

Acceˊleˊrer B de 2 aˋ 1 ⟹ B finit aˋ 1 ⟹ C deˊmarre TOUJOURS aˋ 3.\text{Accélérer }B\text{ de }2\text{ à }1\ \Longrightarrow\ B\text{ finit à }1\ \Longrightarrow\ C\text{ démarre TOUJOURS à }3.

BB attendait déjà. La faire finir plus tôt ne fait qu'allonger son attente : sa marge passe de 11 à 22.

Le chemin B→C→EB\to C\to E passe de 88 à 77 — mais comme A→C→EA\to C\to E reste à 99, c'est ce dernier qui commande.

dureˊe=max⁡(tous les chemins) : diminuer un chemin NON maximal ne change pas le max.\text{durée}=\max(\text{tous les chemins})\ :\ \text{diminuer un chemin NON maximal ne change pas le max.}
Pourquoi accélérer $D$ ne sert à rien non plus

DD commence à 77 et finit à 88. Le projet, lui, dure 99 — c'est EE qui le termine.

Même en rendant DD instantanée (1→01\to0), elle finirait à 77 et le projet durerait toujours 9\mathbf9, imposé par EE.

Il faudrait acceˊleˊrer E, pas D.\text{Il faudrait accélérer }E,\text{ pas }D.

Cas particulier instructif : DD et EE démarrent toutes deux à 77 et sont en parallèle. C'est la plus longue des deux qui compte, donc EE (22) et non DD (11). Réduire la plus courte de deux branches parallèles est toujours sans effet.

⚠️ Le piège : le chemin critique BOUGE

Accélérer une tâche critique fonctionne — mais pas indéfiniment.

Accélérons EE de 22 à 11. Le projet passe à 88. Recalculons les chemins :

chemin avant après
A→C→DA\to C\to D 88 8\mathbf{8}
A→C→EA\to C\to E 9\mathbf{9} 8\mathbf{8}
B→C→DB\to C\to D 77 77
B→C→EB\to C\to E 88 77

Il y a maintenant DEUX chemins critiques, tous deux à 88 : A→C→DA\to C\to D et A→C→EA\to C\to E.

Conséquence : accélérer EE une seconde fois ne rapporterait plus rien — il faudrait accélérer DD aussi, ou bien AA ou CC, qui sont sur les deux chemins.

Apreˋs chaque acceˊleˊration, RECALCULER le chemin critique.\boxed{\text{Après chaque accélération, RECALCULER le chemin critique.}}

C'est l'erreur classique du pilotage de projet : on optimise une fois, on croit pouvoir continuer sur la même tâche, et le gain s'arrête sans qu'on comprenne pourquoi.

La stratégie complète, et son coût

La marche à suivre, à chaque itération :

  1. calculer le chemin critique ;
  2. parmi ses tâches, accélérer la moins chère ;
  3. recalculer — le chemin critique a pu changer ;
  4. recommencer tant que le gain vaut son prix.

Le meilleur candidat ici est CC, et pour une raison structurelle : elle est sur les quatre chemins. L'accélérer bénéficie donc à tous en même temps, alors qu'accélérer EE ne sert que deux chemins sur quatre.

tâche critique sur combien de chemins robustesse du gain
AA 22 (A→C→DA\to C\to D, A→C→EA\to C\to E) moyenne
C\mathbf{C} 4\mathbf{4} — tous la meilleure
EE 22 moyenne

C'est le problème du crashing en gestion de projet : chaque accélération a un coût, et l'on cherche le meilleur rapport gain de durée / coût. Formalisé, c'est un programme linéaire — ce qui referme la boucle avec le chapitre Optimisation.

Réponse : agir sur AA, CC ou EE — chacune fait passer le projet de 99 à 88 ; accélérer BB ou DD ne change RIEN, car elles disposent déjà d'une marge de 11. Et après toute accélération, il faut recalculer : dès que EE passe à 11, le chemin A→C→DA\to C\to D devient critique à son tour.

Réponse. Agir sur A,C,EA,C,E (critiques) ; accélérer BB ou DD est sans effet sur le délai. (Recoupement : marges 11 pour B,DB,D — pur battement ✓)
Faire cet exercice dans l'app →

S'entraîner davantage sur recherche opérationnelle & graphes

18 exercices d'entraînement supplémentaires sur ce chapitre, plus le palier approfondissement, les quiz, le tuteur IA et les PDF à imprimer — dans l'app Maths Post-Bac.