8.1 Arbre couvrant de poids minimum
8.1.1 Le problème
Le problème est le suivant :
entrée : un graphe connexe, non orienté, pondéré (pas forcément positivement) non
orienté G=(S,A) ;
sortie : un arbre couvrant de poids minimal EA, c’est à dire un ensemble d’arêtes E,
qui connecte tous les sommets, et tel que X
(a,b)E
poids(a,b) est minimal.
Remarquez que si le graphe initial est pondéré positivement, un sous-graphe couvrant de
poids minimal est forcément... un arbre couvrant.
Applications :
Circuits électroniques
Réseaux
Exemple 35. Dessinez un graphe. Le graphe représente une ville dans laquelle il n’y a malheu-
reusement pas encore de pistes cyclables. Les nœuds sont des maisons et les arcs représentent
les routes. Le poids d’un arc est la longueur de la route. Le maire souhaite placer des pistes
cyclables entre les maisons de façon à ce qu’il est possible d’aller d’une maison à une autre en
prenant une piste. L’arbre couvrant donne une solution la moins chère.
A
BC
D E F G
H I
4
1
3
11 1
1 1
1
1
25
8.1.2 Algorithme de Kruskal
L’algorithme date de 1956. Kruskal (1928-2010) a aussi travaillé dans d’autres domaines :
statistique et linguistique notamment. Mais il reste vraiment célèbre pour son algorithme de
calcul d’un arbre couvrant minimal, qui est devenu un classique des cours d’algorithmique.
Principe
Le principe est on ne peut plus glouton : on débute avec E=et tant que En’est pas un
arbre, on ajoute à El’arête la plus légère parmi les arêtes non traités si elle ne crée pas de cycles
dans E.
Cela ne vous rappelle rien ? L’algorithme de Kruskal est une généralisation de l’algorithme
de génération de labyrinthe vu en section 5.1.
Au début, comme E=, le sous-graphe en construction n’a pas d’arcs et a donc autant de
composantes connexes que de sommets. Puis lorsque l’on traite une arête {x,y}, on regarde si x
est yne sont pas déjà relié, ie. si xet yne sont pas dans la même composante connexe.
Pour cela, on va utiliser une structure de données abstraite pour représenter une partition
d’un ensemble fini. Il s’agit de union-find vu au chapitre 5 et ses opérations sont :
François Schwarzentruber Page 98 ALGO1 - ENS Rennes
créer_union_find : crée la partition [
sS{{s}} :
find : Trouve la composante de x
union : fusionne les composantes de xet y.
Algorithme
Le pseudo-code de l’algorithme de Kruskal est l’algorithme 28.
Algorithme 28 : Algorithme de Kruskal
Entrées : Un graphe G=(S,A) pondéré non orienté
Sorties : Un ACM (arbre couvrant minimal) de G
CC :=créer_union_find(S)
E:=
L:=tri(A) par ordre croissant des poids.
pour {x,y} ∈ L (dans l’ordre) faire
si CC.f ind(x),CC.f ind(y)alors
E:=E∪ {{x,y}}
CC.union(x,y)
retourner E
Théorème. À la fin, E contient les arêtes d’un ACM.
D´
emonstration.
On va démontrer l’invariant suivant I:
1. il existe TACM tel que ET
2. et pour tout x,yS
xet ysont reliés pas des arêtes dans Essi xet ysont dans la même composante
dans CC.
Initialisation : E=, et il existe un ACM (qui trivialement contient les arêtes de E). Par
ailleurs :
xet ysont reliés par des arêtes de E
ssi (car Eest vide)
x=y
ssi (car CC est la partition composée de singletons)
xet ysont dans la même classe dans CC
Conservation : Supposons que l’invariant Iest vraie avant un tour de boucle en (*).
Montrons qu’il reste vraie après le tour de boucle en ().
()
if CC.f ind(x),CC.f ind(y)then
E:=E∪ {{x,y}}
CC.union(x,y)
endIf
()
1. Occupons nous du point 1. On a ajouté une arête {x,y}àE. On a il existe TACM tel
que E\ {x,y} ⊆ Tet on veut montrer que que le point 1 de l’invariant est conservée,
c’est à dire qu’il existe bien un T0ACM tel que ET0.
François Schwarzentruber Page 99 ALGO1 - ENS Rennes
Si (par chance !) {x,y} ∈ T, alors la première partie de l’invariant est conservée
en prenant T0=T.
Sinon, on construit un ACM T0qui contient E. La construction de T0s’appuie
sur la donnée de T. Voici la situation actuelle :
en noir fin : T
en vert gros : E
y
x
arrête ajouté
On rappelle la caractérisation des arbres :
arbre connexe et |S| − 1 arcs
Comme Test un arbre, il est connexe et xet ysont reliés par un chemin cdans T.
Par le point 2 de Ien (*), comme CC.f ind(x),CC.f ind(y), xet yne peuvent
pas être reliés par uniquement des arêtes de E\ {x,y}. Donc une des arêtes du
chemin cn’est pas dans E. Soit {u,v}une telle arête de T\E(reporté en trait
bleu sur le dessin d’avant).
On construit T0à partir de Ten supprimant cette arête bleu et en ajoutant {x,y}.
Formellement, on définit T0par T0=T∪ {{x,y}} \ {{u,v}}. Ainsi ET0. Voici
T0dessiné en trait noir fin :
y
x
Montrons que T0est un ACM. En eet,
T0est connexe, T0et Tont même nombre d’arêtes (|S| − 1) donc c’est un
arbre.
Comme {u,v}n’a pas encore été choisie mais que {x,y}a été choisi et que
les arêtes sont triées, on a poids({x,y})poids({u,v}). Ainsi : poids(T0)=
poids(T)+poids({x,y})poids({u,v})6poids(T). Donc le poids de T0est
minimal.
Montrons le point 2 de l’invariant. Soit {x,y}l’arête ajouté à E. Montrons que x0et y0
sont reliés pas des arêtes dans Essi x0et y0sont dans la même composante dans CC. On
s’intéresse à deux cas clefs.
Cas où x0était la classe de xety0dans la classe yen ()
François Schwarzentruber Page 100 ALGO1 - ENS Rennes
D’une part, par l’invariant en (), il existe un chemin cxdans E\ {{x,y}} de x0àxet un
chemin de cydans E\{{x,y}} de yày0. On construit alors un chemin de Een concaténant
cx,xyet cy.On a x0et y0sont reliés pas des arêtes dans E.
D’autre part, les classes de xet ysont fusionnées par CC.union(x,y). Donc x0et y0sont
dans la même composante dans CC.
Cas où x0est dans la classe xet y0dans une autre classe que xou yen ()
D’une part, montrons qu’il n’y a pas de chemin dans Ede x0ày0. Par l’absurde, sup-
posons qu’il existe un tel chemin. Si ce chemin est intégralement dans E\ {{x,y}}, alors
par l’invariant, x0et y0devraient être dans la même classe en () ce qui n’est pas le cas.
Donc le chemin dans Ede x0ày0passe par l’arête {x,y}. Mais alors soit y0est dans la
classe de xou y... Non.
D’autre part, les classes de x0et y0ne sont pas fusionnées par CC.
À présent, montrons que Eest un ACM.
D’une part, (S,E) est un arbre.
D’une part (S,E) est connexe. Cela resulte de la connexité de Get du traitement
systématique de toute les arêtes de G. En eet, si x,yS, on sait que xet ysont
reliés dans G:x=x1x2↔ ··· ↔ xny.
On construit alors un chemin de xàyavec des arêtes de Ede la manière suivante.
Pour tout i, si {xi,xi+1} ∈ E, on prend cette arête dans le chemin. Sinon, si {xi,xi+1}<
E, lorsque l’algorithme a traité {xi,xi+1},{xi,xi+1}n’a pas été ajouté à E. On avait xiet
xi+1dans la même composante CC. Donc, l’invariant nous dit qu’il y avait un chemin
de xiàxi+1dans E(il est toujours intégralement composé d’arêtes de Epuisque E
est croissant lors de l’algorithme). Donc on prend ce chemin pour aller de xiàxi+1.
On a ainsi construit un chemin de xàyavec des arêtes de E.
D’autre part, il est acyclique. S’il contenait un cycle, regardons la dernière arête
{x,y}ajouté de ce cycle. Par l’invariant, il existait un chemin de xàydonc l’arête
n’aurait pas dû être ajoutée. Contradiction.
D’autre part, il est minimal. En eet, par l’invariant, il existe T0ACM tel que ET0.
(S,E) est un arbre donc il contient |S| − 1 arêtes. De même pour T0. Donc E=T0.
Complexité
Théorème. L’algorithme de Kruskal s’exécute en
|creer_union_ f ind|+O(Aln(A)) +O(A(|f ind|+|union|)).
D´
emonstration.
Il y a la création de la structure union find, puis le tri, puis une boucle, dont chaque passage
de boucle appelle f ind et union.Autrement dit pour des arbres de type union-find :
|creer_union_f ind|:O(S) ;
f ind et union en O(ln S).
Bilan : Comme |S| − 1≤ |A|, on a dans le pire des cas une complexité en O(Aln(A)). Cela
peut se réécrire en O(Aln(S)) car |A|≤|S|2et donc ln A=2 ln S. Si le tri de Aa déjà été fait
alors la complexité peut être en O(Aln(S)) avec la structure union find avec compression de
chemin.
François Schwarzentruber Page 101 ALGO1 - ENS Rennes
8.1.3 Algorithme de Prim
L’algorithme date de 1957... Kruskal a aussi participé à son élaboration. Attention ! Il res-
semble comme deux gouttes d’eau à l’algorithme Dijkstra ! Ce n’est pas sans raison : Dijkstra
s’en inspiré en 1959. On utilise une stratégie gloutonne : on ajoute à E(arbre qui grossit pendant
l’algorithme) un arc uEt<Ede poids minimum.
Algorithme 29 : Algorithme de Prim
Entrées : Un graphe G=(S,A)
Sorties : Un ACM de G
pour sSfaire
cout[s] :=+
pred[s] :=
u0:=un sommet de G
cout[u0] :=0
F:=filedepriorité (S,cout)
tant que F,faire
t:=F.défilemin
pour tout u tel que t uAfaire
si cout[u]>poids(tu)alors
cout[u] :=poids(tu)
F.notifierDiminution(u)
pred[u] :=t
retourner pred
Au niveau de la complexité, cela se passe comme pour l’algorithme de Djikstra :
Théorème.
L’algorithme eectue O(|S|+|S||défiler_min|+|file_créer|+|A||MàJ|).
Remarque.
Avec une implémentation sous forme de tableau, on a une complexité en O(|S|2).
Sous forme d’un tas, c’est O((|S|+|A|) log(|S|)).
Sous forme d’un tas de Fibonacci, c’est O(|S|log(|S|)+|A|).
8.1.4 Kruskal VS Prim
On note les complexités (avec les structures de données qui donnent les meilleures com-
plexités) et les avantages des deux algorithmes.
Kruskal Prim
O(Aln S)O(Sln S+A)
graphe creux graphe dense
rapide si déjà les arcs sont déjà triés on a toujours une solution partielle
8.2 Formules de Horn
[DPV06], p. 157 Dans cette section, on veut faire du raisonnement automatique. Alfred
Horn (1918-2001) est un mathématicien, logicien américain décrit en 1951 les clauses de Horn
comme fondement de la programmation logique. Les clauses de Horn sont un fragment logique
qui permettent d’exprimer des règles qui sont sous la forme suivante :
Des implications comme abcd. Cette expression signifie ‘Si a,b,csont vraies
alors dest vraie’ ;
François Schwarzentruber Page 102 ALGO1 - ENS Rennes
1 / 5 100%
La catégorie de ce document est-elle correcte?
Merci pour votre participation!

Faire une suggestion

Avez-vous trouvé des erreurs dans linterface ou les textes ? Ou savez-vous comment améliorer linterface utilisateur de StudyLib ? Nhésitez pas à envoyer vos suggestions. Cest très important pour nous !