Arbre couvrant minimal

publicité
Arbre couvrant minimal
(Minimal spanning tree)
2704
BOS
867
849
PVD
ORD
337
1391
1464
1235
144
JFK
1258
184
802
SFO
LAX
187
740
621
1846
BWI
1090
DFW
946
1121
MIA
2342
1
Arbre couvrant minimal
Définitions
L'algorithme de Prim-Jarnik
L'algorithme de Kruskal
2
1
Arbre couvrant minimal
Sous-graphe couvrant

Arbre couvrant

Arbre couvrant d’un graphe
pondéré avec la somme des
poids des arêtes qui
constituent l'arbre est
minimal
10
1
DEN
Sous-graphe couvrant qui
est un arbre
Arbre couvrant minimal (ACM)

ORD
Sous-graphe d’un graphe G
contenant tous les sommets
de G
PIT
6
9
7
3
STL
4
DCA
5
8
DFW
2
ATL
Applications


Réseaux informatiques
Réseaux routiers
3
Propriété de cycles
Propriété de cycles:
 Soit T un arbre
couvrant minimal d’un
graphe pondéré G
 Soit e une arête de G
n’appartenant pas à T et
soit C le cycle obtenu
lorsqu’on ajoute e à T
 Pour chaque arête f
dans C, poids(f) ≤ poids(e)
Preuve:
Par contradiction
 Si poids(f) > poids(e) nous
pouvons obtenir un
arbre couvrant de plus
petit poids en
remplaçant e par f
f
2
8
4
C
6
9
3
e
8
7
7
Remplaçant f avec e produit
un mieux arbre couvrant
f
2
6
8
4
C
9
3
8
e
7
7
4
2
Propriété de cycles
Dans tout cycle du graphe,
les arêtes faisant partie
d’un ACM ont des poids
inferieurs aux autres
arêtes (en pointillé)
ORD
10
1
PIT
DEN
6
9
7
3
DCA
STL
4
5
8
DFW
2
ATL
5
Propriété de partition
Propriété de partition:
Considérons une partition des sommets
de G en deux ensembles U et V. Soit e
une arête de poids minimal entre U et V.
Alors, il existe un arbre couvrant
minimal de G contenant e
Preuve:
 Soit T un arbre couvrant minimal de G
 Si T ne contient pas e, soit C le cycle
formé par l’addition de e à T et soit f
une arête de C entre U et V
 Par la propriété de cycles,
poids(f) ≤ poids(e)
 Alors, poids(f) = poids(e)
 Nous obtenons un autre ACM en
remplaçant f par e
U
f
V
7
4
9
5
2
8
8
3
e
7
Remplacer f avec e
donne un autre ACM
U
2
f
V
7
4
9
5
8
8
3
e
7
6
3
L’algorithme de Prim-Jarnik
L'algorithme de Prim-Jarnik pour calculer un ACM
est similaire à l'algorithme de Dijkstra
Nous supposons que le graphe est connexe
Nous choisissons un sommet arbitraire s et nous
faisons grossir l’ACM comme un nuage de
sommets, commençant de s
Nous emmagasinons avec chaque sommet v une
étiquette d(v) représentant le plus petit poids
d'une arête connectant v à n'importe quel sommet
dans le nuage (comme opposé à la somme totale
des poids sur un chemin du sommet de départ
jusqu’à u).
7
L’algorithme de Prim-Jarnik
Pour chaque étape


Nous ajoutons au nuage le sommet extérieur u
ayant la plus petite étiquette de distance
Nous mettons à jour les étiquettes des
sommets adjacents à u
8
4
Utiliser une file à priorité Q dont les clés sont les
étiquettes D, et dont les éléments sont des paires
sommet-arête.

Clé : distance

Élément: sommet
Tout sommet v peut être le sommet de départ.
On continue à initialiser toutes les valeurs de D[u] à
“infini”, mais nous initialisons aussi E[u] (l’arête associé à
u) à “null”.
Retourne l’arbre recouvrant minimal T.
Nous pouvons réutiliser le code produit par Dijkstra, et ne changer
que quelques parties. Observons le pseudo-code....
9
Algorithm PrimJarnik(G):
Entrée: Un graphe pondéré G.
Sortie: Un ACM T pour G.
pick any vertex v of G
{grow the tree starting with vertex v}
T ← {v}
D[u] ← 0
E[u] ← ∅
for each vertex u ≠ v do
D[u] ← ∞
let Q be a priority queue that contains vertices, using the D labels as keys
while Q ≠ ∅ do {pull u into the cloud C}
u ← Q.removeMinElement()
add vertex u and edge E[u] to T
for each vertex z adjacent to u do if z is in Q
{perform the relaxation operation on edge (u, z) }
if weight(u, z) < D[z] then
D[z] ←weight(u, z)
E[z] ← (u, z) change the key of z in Q to D[z]
return tree T
10
5
Exemple
2
D
7
B
0
A
B
A
A
F
8
7
2
∞
F
E
B
3
0
A
F
8
8
7
4
9
5
C
5
2
7
7
D
7
E
7
∞
3
E
7
4
7
5
4
9
5
C
8
0
8
8
B
2
7
9
5
C
5
2
D
7
∞
7
D
7
3
E
7
2
0
F
8
8
2
4
9
8
C
5
2
∞
4
3
7
11
Exemple (suite)
2
2
B
5
A
7
4
9
5
C
F
8
8
0
D
7
7
E
4
3
3
2
2
B
5
A
7
4
9
5
C
F
8
8
0
D
7
7
E
4
3
3
12
6
Prim-Jarnik…
Pourquoi il marche
Ceci est une application de la propriété de
Cycles!
Soit (u,v) l’arête minimale dans quelques
itérations. S’il y a un ACM ne contenant pas
(u,v), alors (u,v) complète un cycle. Puisque
(u,v) a été considéré avant quelque autre
arête connectant v au groupe, il doit avoir
un poids inférieur ou égal au poids de
l’autre arête. Un nouveau ACM peut être
formé par permutation
13
Analyse de complexité
Opérations sur les graphes
 Méthode incidentEdges est appelée une fois pour chaque
sommet
Opérations d’étiquetage
 Nous plaçons/obtenons les étiquettes de sommet z O(deg(z))
fois
 placer/obtenir les étiquettes prend O(1)
Opérations de file de priorité
 Chaque sommet est inséré une fois et enlevé une fois de la
file à priorité, où chaque insertion ou suppression prend
O(log n)
 La clé d'un sommet w dans la file à priorité est modifiée au
plus deg(w) fois, où chaque changement de clé prend O(log n)
14
7
L’algorithme de Prim-Jarnik est exécuté en O((n + m) log n)
si le graphe est
représenté par la structure de liste d’adjacence
Rappelez-vous que S v deg(v) = 2m
Le temps d’exécution est O(m log n) parce que le graphe est connexe
15
Dijkstra vs. Prim-Jarnik
Algorithm DijkstraShortestPaths(G, s)
Q ← new heap-based priority queue
for all v ∈ G.vertices()
if v = s
setDistance(v, 0)
else
setDistance(v, ∞)
setParent(v, ∅)
l ← Q.insert(getDistance(v), v)
setLocator(v,l)
while ¬Q.isEmpty()
u ← Q.removeMin()
for all e ∈ G.incidentEdges(u)
z ← G.opposite(u,e)
r ← getDistance(u) + weight(e)
if r < getDistance(z)
setDistance(z,r)
setParent(z,e)
Q.replaceKey(getLocator(z),r)
Algorithm PrimJarnikMST(G)
Q ← new heap-based priority queue
s ← a vertex of G
for all v ∈ G.vertices()
if v = s
setDistance(v, 0)
else
setDistance(v, ∞)
setParent(v, ∅)
l ← Q.insert(getDistance(v), v)
setLocator(v,l)
while ¬Q.isEmpty()
u ← Q.removeMin()
for all e ∈ G.incidentEdges(u)
z ← G.opposite(u,e)
r ← weight(e)
if r < getDistance(z)
setDistance(z,r)
setParent(z,e)
Q.replaceKey(getLocator(z),r)
16
8
L’algorithme de Kruskal
Chaque sommet est emmagasiné initialement comme son propre
groupe.
A chaque itération, l’arête de poids minimal dans le graphe est
ajoutée à l'arbre couvrant si elle relie 2 groupes distincts.
L'algorithme se termine quand tous les sommets sont dans le
même groupe.
Ceci est une application de la propriété de partition!
Si l’arête minimale dans quelques itérations est (u,v), alors si
nous considérons une partition de G avec u dans un groupe
et v dans l’autre, alors la propriété de partition dit qu’il doit y
avoir un ACM contenant (u,v)
17
L’algorithme de Kruskal
Une file de priorité
emmagasine les
arêtes extérieures
(hors du nuage)
 clé: poids
 élément: arête
À la fin de
l’algorithme
 On se retrouve
avec un nuage
qui entoure l’ACM
 Un arbre T qui
est notre ACM
Algorithm KruskalMST(G)
for each vertex V in G do
define a Cloud(v) of  {v}
let Q be a priority queue.
Insert all edges into Q using their
weights as the key
T∅
while T has fewer than n-1 edges do
edge e = T.removeMin()
Let u, v be the endpoints of e
if Cloud(v) ≠ Cloud(u) then
Add edge e to T
Merge Cloud(v) and Cloud(u)
return T
18
9
Structure de données pour
l’algorithme de Kruskal
L’algorithme maintient une forêt d’arbres
Une arête est acceptée, si elle relie deux arbres
distincts
Nous avons besoin d’une structure de données qui
maintient une partition c.-à-d. une collection
d’ensembles disjoints, avec les opérations:
-find(u): retourne l’ensemble
contenant u
-union(u,v): remplace les ensembles
contenant u et v
par leur union
19
Représentation d’une
partition:
Chaque élément d’un ensemble est mis en mémoire dans une
séquence (l’ensemble pointe vers la séquence contenant ces
éléments)
Chaque élément à un pointeur vers l’ensemble



L’opération find(u) se fait en O(1) et retourne l’ensemble
dont u fait partie
Pour l’opération union(u,v), nous bougons les éléments du
plus petit ensemble dans la séquence du plus grand
ensemble et nous mettons à jour leur pointeur
La complexité en temps de union(u,v) est min(nu,nv), où nu et
nv sont les tailles des ensembles contenant u et v
Chaque fois qu’un élément est traité, il est mis dans un
ensemble de taille au moins double, donc chaque élément est
traité au plus log n fois
20
10
Implémentation à base de partition
Une version à base de partition de l’algorithme de
Kruskal exécute les fusions du nuage comme des
union(u,v) et les tests comme des find(u).
Algorithm Kruskal(G):
Entrée: Un graphe pondéré G.
Sortie: Un ACM T pour G.
Soit P une partition des sommets de G, où chaque sommet est dans un ensemble séparé.
Soit Q une file à priorité gardant en mémoire les arêtes de G, ordonnées selon leur poids
Soit T un arbre initialement vide
while Q n’est pas vide do
(u,v) ← Q.removeMinElement()
if P.find(u) != P.find(v) then
Ajouter (u,v) à T
P.union(u,v)
return T
Temps: O((n+m)log n)
21
Exemple
5
1
6
C 11
10
9
5
1
2
C 11
7
A
E
6
F
3
D
H
1
2
A
6
5
H
C 11
10
2
G
9
7
F
3
8
B
4
4
E
D
10
G
9
7
H
D
8
5
F
3
G
8
B
4
E
C 11
10
B
A
9
7
A
1
G
8
B
4
E
6
F
3
D
H
2
22
11
Exemple (suite)
6
9
C 11
7
10
H
F
3
D
H
4
E
6
F
3
H
D
10
2
4 etapes
et
ap
es
6
C 11
7
A
4
E
9
5
1
2
G
8
5
F
3
D
10
B
A
E
C 11
7
A
1
9
G
8
B
4
1
2
A
G
8
B
2
5
1
G
8
B
5
9
C 11
7
10
4
E
6
F
3
D
H
2
23
12
Téléchargement