Arbres et arbres couvrants
Ce que ce chapitre apporte 7 points
- Reconnaître un arbre par n'importe laquelle de ses définitions équivalentes.
- Utiliser la relation m = n - 1 pour conclure sans dessiner.
- Distinguer arbre couvrant et arbre couvrant minimal.
- Dérouler Kruskal et Prim, et dire ce qui les distingue.
- Expliquer pourquoi un algorithme glouton donne ici l'optimum exact.
- Employer une structure union-trouve pour détecter les cycles en temps quasi constant.
- Compter les liaisons redondantes d'un réseau connexe.
L'arbre, quatre définitions pour un seul objet
Un arbre est un graphe connexe et sans cycle.
Cette définition en cache trois autres, toutes équivalentes pour un graphe à sommets. C'est le genre de théorème qui sert constamment, parce qu'il permet de vérifier la propriété la plus commode.
| Formulation | Ce qu'elle permet de vérifier vite |
|---|---|
| connexe et sans cycle | la définition |
| connexe avec exactement arêtes | compter les arêtes suffit |
| sans cycle avec exactement arêtes | compter les arêtes suffit |
| un unique chemin élémentaire entre chaque paire | l'unicité du trajet |
Six sommets, cinq arêtes, connexe : c'est un arbre. Ajouter n'importe quelle arête crée un cycle ; en retirer une coupe le graphe en deux.
Un arbre est exactement à la limite. Un arbre est maximalement sans cycle : toute arête ajoutée crée un cycle.
Il est en même temps minimalement connexe : toute arête retirée le déconnecte.
Ces deux phrases disent la même chose et expliquent pourquoi est à la fois le minimum d'arêtes pour être connexe et le maximum pour rester sans cycle.
On ne peut pas conclure : est nécessaire, pas suffisant. Le graphe pourrait être un triangle plus une composante à part, ce qui donne bien 11 arêtes sans être un arbre.
Il faut une information de plus : connexe, ou sans cycle. Avec l'une des deux, c'est un arbre.
Feuilles et racine
Un sommet de degré 1 s'appelle une feuille. Tout arbre ayant au moins deux sommets en possède au moins deux. Aucun sommet n'y est de degré 0, puisque l'arbre est connexe ; si au plus un sommet était de degré 1, tous les autres seraient de degré au moins 2, et la somme des degrés vaudrait au moins , alors qu'elle vaut .
Un arbre n'a pas de racine en soi. Enraciner un arbre, c'est choisir un sommet comme origine, ce qui oriente implicitement toutes les arêtes et donne les notions de père, de fils, de profondeur. C'est un choix de lecture, pas une propriété du graphe.
Un réseau connexe relie 12 sites par 14 liaisons. Combien de liaisons faut-il couper, au minimum, pour qu'il ne reste aucune boucle sans isoler aucun site ?
Arbre couvrant
Un arbre couvrant d'un graphe connexe est un sous-graphe qui contient tous les sommets de , et qui est un arbre.
Si est pondéré, un arbre couvrant minimal est un arbre couvrant dont la somme des poids est la plus petite possible.
Tout parcours en produit un gratuitement : l'arbre de parcours du chapitre précédent, formé des arêtes par lesquelles chaque sommet a été découvert, est un arbre couvrant. Mais rien ne garantit qu'il soit de poids minimal, puisque le parcours ignore les poids.
Les liaisons redondantes d'un réseau
Un graphe connexe qui n'est pas un arbre a des arêtes en trop. Si l'on en garde un arbre couvrant, chaque arête restée hors de l'arbre y referme exactement un cycle. Un graphe connexe à sommets et arêtes porte donc cycles indépendants : c'est le nombre de liaisons redondantes d'un réseau, celles qu'on peut perdre une à une sans isoler personne. Un réseau de 12 sites et 18 liaisons en a ; un arbre n'en a aucune, et la moindre coupure le sépare en deux morceaux.
L'exemple du chapitre
Voici le graphe qui servira d'exemple : huit liaisons possibles entre six sites, avec leur coût. Les coûts sont tous différents, ce qui aura son importance.
Kruskal, arête par arête
Trier les arêtes par poids croissant, puis les examiner une par une : on garde une arête si elle ne crée pas de cycle avec celles déjà retenues, sinon on la jette.
On s'arrête quand on a arêtes.
Kruskal est un algorithme glouton : à chaque étape, il fait le choix qui paraît le meilleur sur le moment, ici l'arête la moins chère encore disponible, et ne revient jamais sur ce choix.
Sur l'exemple, les arêtes triées par poids croissant valent 1, 2, 3, 4, 5, 8, 10 et 11 : la figure les liste dans cet ordre sous le dessin, chacune avec son état. Kruskal ne part d'aucun sommet : il prend E -- D, la moins chère de tout le graphe, puis A -- C, qui ne la touche pas. Deux morceaux séparés coexistent alors, chacun de sa couleur, jusqu'à ce que C -- E les recolle.
En gras : les arêtes retenues ; tiretées en rouge : les rejetées ; en pointillé : celles qui ne seront pas examinées. Chaque morceau de plus d'un sommet a sa couleur et son numéro ; ★ marque son représentant, ce que rend trouver.
- E-D1à examiner
- A-C2à examiner
- C-E3à examiner
- A-B4à examiner
- B-C5à examiner
- E-F8à examiner
- B-D10à examiner
- D-F11à examiner
A -- C, compter les morceaux : deux, de deux couleurs, chacun avec un sommet marqué d'une étoile, qui le représente. Au pas de B -- C, lire le récit : les deux extrémités ont le même représentant, A, et c'est pour cela que l'arête est rejetée, pas pour son poids.Cliquer ensuite le poids de
B -- C, le passer à 3 et dérouler de nouveau : c'est maintenant A -- B, de poids 4 seulement, qui est rejetée, et l'arbre pèse 17. À 4, les deux arêtes pèsent autant : la figure signale alors un second arbre minimal, de même poids.
L'arbre obtenu pèse . L'arête B -- C de poids 5 a été rejetée : ses deux extrémités étaient déjà reliées par A -- C et A -- B, donc la retenir aurait fermé un triangle. Les arêtes de poids 10 et 11 ne sont même pas examinées : l'arbre a ses arêtes dès E -- F.
Couper les sommets en deux groupes, de n'importe quelle façon. L'arête de poids minimal qui traverse la coupe appartient à un arbre couvrant minimal. Chaque arête retenue par Kruskal est exactement de cette forme : la plus légère qui relie un morceau au reste du graphe, puisque toute arête plus légère a déjà été examinée.
C'est ce théorème qui transforme une heuristique en algorithme exact, et il vaut la peine d'être su : il justifie aussi Prim.
Détecter le cycle : union-trouve
Le seul point délicat de Kruskal est le test « cette arête crée-t-elle un cycle ? ». Le refaire par un parcours à chaque arête coûterait . La bonne structure répond en temps quasi constant.
Une structure union-trouve maintient une partition d'un ensemble en groupes disjoints, avec deux opérations : trouver(x) donne le représentant du groupe de x, et unir(x, y) fusionne deux groupes.
Une arête crée un cycle si et seulement si ses deux extrémités ont déjà le même représentant.
Ce sont les morceaux colorés de la figure de Kruskal, et l'étoile y marque le représentant de chacun ; le récit de chaque pas écrit les deux appels à trouver, et c'est leur comparaison, et elle seule, qui rejette B -- C. Concrètement, chaque groupe est rangé comme un petit arbre. Chaque sommet note son père, et le représentant est la racine, le seul sommet qui est son propre père. trouver(x) remonte de père en père jusqu'à elle. Pour unir deux groupes, on accroche la racine de l'un sous la racine de l'autre, jamais un sommet quelconque : réécrire le père d'un sommet qui n'est pas une racine le détacherait de son groupe, et le test de cycle se mettrait à mentir. Les deux raffinements du code ci-dessous, l'union par rang et la compression de chemin, ne changent rien au résultat : ils gardent ces petits arbres plats, et c'est ce qui rend chaque test quasi instantané.
Kruskal examine une arête dont les deux extrémités sont déjà dans le même groupe. Il…
Prim, sommet par sommet
Partir d'un sommet quelconque et faire grossir un seul arbre : à chaque étape, ajouter l'arête de poids minimal qui relie l'arbre à un sommet encore extérieur.
La différence avec Kruskal se résume en une phrase : Kruskal fait grandir plusieurs morceaux qui finissent par se rejoindre, Prim fait grandir un seul morceau depuis le départ.
Plein : les sommets de l'arbre. En gras : ses arêtes ; tiretées : les arêtes au bord de l'arbre, entre lesquelles Prim choisit la plus légère ; en pointillé : les arêtes devenues intérieures.
- (2, A, C)
- (4, A, B)
(poids, u, v) du code plus bas. Au cinquième pas, l'entrée (5, C, B) ressort alors que B est déjà dans l'arbre : elle est jetée.Cliquer ensuite un autre sommet pour en faire le départ : l'ordre d'ajout change, l'arbre reste le même. Enfin, passer à la vue « comparer » : depuis
B, l'arbre des plus courts chemins garde B -- C et pèse 21 au lieu de 18, mais chaque site y est au plus près de B.
Le résultat est le même arbre, de poids 18, mais l'ordre d'ajout diffère : Kruskal a pris E -- D en premier, parce qu'elle est la moins chère de tout le graphe ; Prim ne l'a prise qu'en troisième, une fois E entré dans son arbre. Que l'arbre soit le même n'est pas un hasard : les poids sont ici tous distincts, et dans ce cas l'arbre couvrant minimal est unique (la fin du chapitre dit pourquoi), donc les deux algorithmes ne peuvent que tomber dessus.
| Kruskal | Prim | |
|---|---|---|
| Fait grandir | plusieurs morceaux | un seul arbre |
| Structure clé | union-trouve | file de priorité |
| Complexité | , dominée par le tri | avec un tas, avec un simple tableau |
| Meilleur sur | graphe creux | graphe dense, dans sa version à tableau |
À chaque étape, Prim doit retrouver la plus légère des arêtes qui bordent l'arbre. Le code les range dans une structure faite pour cela.
Une file de priorité est une réserve dont on retire toujours l'élément de plus petite valeur, et non le plus ancien comme dans une file ordinaire. En Python, le module heapq la réalise sur une simple liste, rangée en tas : heapify(liste) range d'un coup une liste existante, heappush(tas, x) ajoute un élément, heappop(tas) retire le plus petit, ces deux dernières en . Un triplet (poids, u, v) se compare d'abord par son poids, ce qui suffit à ranger des arêtes.
Le mot « tas » désigne ici cette structure de données, sans rapport avec la zone de mémoire du même nom dans le parcours sur le langage C.
Prim n'est pas l'algorithme de plus court chemin du chapitre suivant. Prim compare le poids de l'arête ; l'algorithme de Dijkstra comparera la distance cumulée depuis le départ. Une seule expression changera dans le code, et le résultat n'aura plus le même sens.
Des poids égaux ouvrent plusieurs solutions. Si deux arêtes ont le même poids, l'arbre minimal peut ne pas être unique : il y en a alors plusieurs, tous de même poids total.
L'arbre couvrant minimal donne-t-il le plus court chemin entre deux sommets ?
Mettre en pratique
Un graphe a 12 sommets et 11 arêtes. Est-ce un arbre ?
On ne peut pas conclure. La relation est nécessaire mais pas suffisante.
Contre-exemple : un triangle sur trois sommets, plus un arbre à neuf sommets et huit arêtes, séparément. Total : 12 sommets, 11 arêtes, et ce n'est pas un arbre puisque le graphe n'est ni connexe ni sans cycle.
Avec une information de plus, connexe ou sans cycle, la conclusion devient immédiate : c'est un arbre.
Pourquoi tout arbre d'au moins deux sommets a-t-il au moins deux feuilles ?
Par le lemme des poignées de main. Un arbre a arêtes, donc la somme des degrés vaut .
Si tous les sommets étaient de degré au moins 2, la somme vaudrait au moins , ce qui est strictement plus grand. Il y a donc au moins un sommet de degré 1.
Pour en obtenir deux : aucun sommet n'est de degré 0, puisque l'arbre est connexe et a au moins deux sommets. S'il n'y avait qu'une seule feuille, tous les autres sommets seraient de degré au moins 2, et la somme vaudrait au moins . Contradiction.
Kruskal examine une arête dont les deux extrémités sont dans le même groupe. Que fait-il et pourquoi ?
Il la rejette.
Si les deux extrémités ont déjà le même représentant dans la structure union-trouve, c'est qu'un chemin les relie déjà parmi les arêtes retenues. Ajouter celle-ci fermerait donc un cycle, et un arbre n'en contient aucun.
Ce rejet est correct même si l'arête est légère : la propriété de coupe garantit que les arêtes déjà retenues, toutes plus légères ou de même poids, appartiennent bien à un arbre minimal.
Quelle différence entre l'arbre couvrant minimal et l'arbre des plus courts chemins ?
Ils optimisent deux choses différentes.
L'arbre couvrant minimal minimise la somme totale des poids des arêtes retenues. C'est le bon objet pour « poser le moins de câble possible ».
L'arbre des plus courts chemins depuis un sommet , que l'algorithme de Dijkstra construit au chapitre suivant, minimise, pour chaque sommet, la distance depuis . C'est le bon objet pour « aller vite depuis ».
Sur un même graphe, les deux diffèrent en général. Sur l'exemple du chapitre, l'arbre des plus courts chemins depuis B garde la liaison B-C (5) au lieu de A-C (2) : chaque site y est au plus près de B, mais l'arbre pèse , contre 18 pour l'arbre minimal. À l'inverse, dans l'arbre minimal, aller de B à C coûte 6 au lieu de 5.
C'est aussi ce qui sépare l'arbre des commutateurs de l'introduction de l'arbre minimal. Trois commutateurs, dont l'un est la racine : deux liaisons de coût 4 relient la racine aux deux autres, une liaison de coût 2 relie ces deux-là entre eux. Chaque commutateur garde son chemin le moins cher vers la racine, la liaison directe de coût 4, et l'arbre retenu pèse 8 ; l'arbre minimal garde la liaison de coût 2 et une seule des deux autres, pour un poids de 6.
Quand préférer Prim à Kruskal ?
Sur un graphe dense, où approche .
Kruskal commence par trier les arêtes, ce qui coûte : sur un graphe dense, cela fait de l'ordre de .
Prim avec un tas coûte , et avec une implémentation par tableau sur graphe dense, , ce qui est meilleur.
Sur un graphe creux, où , les deux sont équivalents et Kruskal est souvent plus simple à écrire correctement.
L'arbre couvrant minimal est-il unique ?
Oui si tous les poids sont distincts. Non en général.
Avec des poids tous différents, la propriété de coupe devient plus forte : l'arête la plus légère qui traverse une coupe appartient à tout arbre couvrant minimal. Si un arbre minimal ne la contenait pas, on pourrait l'y ajouter : elle fermerait un cycle, qui traverse forcément la coupe une seconde fois, par une arête plus lourde. Retirer cette arête plus lourde donnerait un arbre couvrant plus léger, ce qui est impossible.
Or chaque arête retenue par Kruskal est la plus légère d'une coupe, celle qui sépare son morceau du reste du graphe. Les arêtes retenues appartiennent donc à tous les arbres minimaux, qui n'ont eux-mêmes que arêtes : il n'y en a qu'un.
Avec des poids répétés, plusieurs arbres peuvent atteindre le même poids total minimal. C'est pourquoi Kruskal et Prim peuvent renvoyer des arbres différents sur un tel graphe, sans qu'aucun ne soit faux.
Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?
Dans la bibliothèque d'exercices
Kruskal arête par arête, union-trouve, et le compte des arêtes d'un arbre.
- Kruskal, arête par arêteNiveau 3
- Compter les arêtes d'un arbreNiveau 2
- Débogage : une fusion qui oublie les racinesNiveau 4
- Prim, depuis un autre siteNiveau 2
- Vérifier un plan de câblageNiveau 3
- Raccorder les hameaux au moindre coûtNiveau 3