MP option informatique 1) Exercice 12 (Algorithme de Kruskal) Graphes a) Le graphe G étant connexe, on peut considérer l’ensemble de ses sous-graphes connexes qui ne sera pas vide (mais est fini). On considère dans cet ensemble un sous-graphe qui a le moins d’arêtes. Il est nécessairement acyclique car s’il avait un cycle, on pourrait enlever une arête sans ” casser ” la connexité. b) A tout moment le sous-graphe (V, Ek ) est acyclique par définition. Montrons que le graphe final (noté Gf = (V, Ef )) est connexe. Par l’absurde, supposons qu’il ne le soit pas. On considère alors deux composantes connexes de Gf . Elles sont reliés par un chemin (dans G). Soit e une arête de G qui ” sort ” d’une composante connexe (il suffit de prendre la première arête du chemin considéré ci-dessus). De ce fait, ajouter e à Gf ne va pas créer un cycle - cela signifie qu’au moment où on a considéré e (pour ne pas l’ajouter) elle ne créait pas de cycle. C’est donc absurde. Finalement Gf est bien un arbre. 2) L’ensemble des arbres couvrant est un sous-ensemble de l’ensemble des sous-graphes. Il est donc fini. Il y a donc des arbres couvrants de poids minimal. 3) a) b) Considérons C1 , . . . , Cp les composantes connexes de (V, E1 ). • S’il existe une arête de E2 qui connecte deux composantes connexes distinctes alors on peut ajouter cette arête sans créer un cycle. • Supposons à l’inverse que toute arête de E2 connecte deux sommets d’une même composante connexe. Comme |E2 | > |E1 | il existe une des composantes connexe où il y a (strictement) plus d’arêtes de E2 que de E1 . En se restreignant à cette composante connexe, on voit que E1 engendre un arbre (connexe et sans cycle). Il ne se peut donc pas que E2 ait plus d’arêtes. On ne peut finalement pas être dans ce cas. c) Montrons par récurrence sur k que pour tout arbre couvrant T de poids minimal, la somme des poids des k arêtes les plus légères de T est supérieure ou égale à la somme des k arêtes de l’arbre renvoyé par l’algorithme. Fixons les notations. On pose (e1 , . . . , em ) les arêtes du graphes (classées par poids croissant). On note i1 ≤ i2 ≤ · · · ≤ in−1 les indices des arêtes dans T et j1 ≤ · · · ≤ jn−1 les arêtes du graphe renvoyé par l’algorithme. • Initialisation : Pour k = 0 c’est vrai • Hérédité : on suppose que la propriété est vraie pour un k donné. C’est-à-dire que p(ej1 ) + · · · + p(ejk ) ≤ p(ei1 ) + · · · + p(eik ) D’après la question précédente, on sait qu’il existe une arête eα dans {ei1 , . . . , eik+1 } \ {ej1 , . . . , ejk } telle que si on l’ajoute à {ej1 , . . . , ejk } on obtient un graphe sans cycle. Comme elle n’a de fait pas été ajoutée alors p(ejk ) ≤ p(eα ) De ce fait, p(ejk+1 ) ≤ p(eα ). On a donc p(ej1 ) + · · · + p(ejk+1 ) ≤ p(ei1 ) + · · · + p(eik ) + p(eα ) ≤ p(ei1 ) + · · · + p(eik+1 ) car p(eα ) ≤ p(eik+1 ). Lycée Chateaubriand 1/3 MP option informatique Exercice 12 (Algorithme de Kruskal) Graphes d) On implémente l’algorithme de Kruskal. Il faut d’abord construire la liste des arêtes triées selon leur poids. On construit cette liste par : let creeListeArete g = let n = vect_length g in let rec ajoute l i = match i , l with | i , [] when i = n -> [] | i , [] -> ajoute g .( i + 1) ( i + 1) | i ,( j , p ) :: q -> (p , i , j ) :: ajoute q i in ajoute g .(0) 0;; qui permet de créer une liste des arêtes sous la forme de triplets : poids, debut, fin. On peut alors faire (par exemple) un tri fusion let rec division liste = match liste with |[] - >[] ,[] | a ::[] - > liste ,[] | a :: b :: c - > let ( l1 , l2 ) = division c in a :: l1 , b :: l2 ;; let rec fusionTri liste1 liste2 = match liste1 , liste2 with |[] , _ - > liste2 ; |_ ,[] - > liste1 ; |( p1 , i1 , j1 ) :: q1 , ( p2 , i2 , j2 ) :: q2 - > if p1 < p2 then ( p1 , i1 , j1 ) ::( fusionTri q1 liste2 ) else ( p2 , i2 , j2 ) ::( fusionTri liste1 q2 ) ;; let rec tri_fusion liste = match liste with |[] - >[]; | a ::[] - > liste ; | _ -> begin let ( liste1 , liste2 ) = division liste in fusionTri ( tri_fusion ( liste1 ) ) ( tri_fusion ( liste2 ) ) ; end ;; Lycée Chateaubriand 2/3 MP option informatique Exercice 12 (Algorithme de Kruskal) Graphes Il ne reste plus qu’à écrire le programme en utilisant la structure Union-Find. let kruskal g = let listeArete = tri_fusion ( creeListeArete g ) in let n = vect_length g in let t = creer2 n in let rec traiteListe l = match l with | [] -> [] | (p , i , j ) :: q -> if representant2 t i = representant2 t j then traiteListe q else ( fusion2 t i j ; (p , i , j ) :: traiteListe q ) in traiteListe listeArete ;; Lycée Chateaubriand 3/3