CSI2510 Structures de données et algorithmes Plus court chemin

Transcription

CSI2510 Structures de données et algorithmes Plus court chemin
Graphe pondéré
CSI2510
Structures de données et
algorithmes
Les poids des arêtes d’un graphe représentent des
distances, des coûts, etc.
Exemple d’un graphe pondéré non-orienté:
Dans un graphe des route aériennes, le poids d'une
arête représente la distance en miles entre les
aéroports de chaque extrémité
Plus court chemin
SFO
LGA
HNL
LAX
1
Plus court chemin
DFW
MIA
2
CSI2510 -- PCC
Propriétés
Étant donné un graphe pondéré et deux sommets u
et v, nous voulons trouver un chemin de poids total
minimal entre u et v
Applications
Propriété 1:
Un sous-chemin d’un plus court chemin est aussi un plus court
chemin
Propriété 2:
Les réservations de vol
Directions de conduite
Routage des paquets d‘Internet
L’ensemble des plus courts chemins d’un sommet à tous les
autres sommets forme un arbre
Exemple:
Exemple:
Plus court chemin entre Providence et Honolulu
SFO
Un arbre des plus courts chemins de Providence
PVD
ORD
SFO
LGA
HNL
LAX
DFW
CSI2510 -- PCC
PVD
ORD
LGA
HNL
PVD
ORD
LAX
DFW
MIA
3
CSI2510 -- PCC
MIA
4
1
Algorithme de Dijkstra
Algorithme de Dijkstra
L’algorithme conserve l’ensemble des sommets pour lesquels la
distance a été calculée, appelé nuage (cloud) C
La distance entre un sommet v à un autre sommet
s est la longueur du plus court chemin entre s et v
L’algorithme de Dijkstra calcule la distance entre
un sommet donnée s de départ et tous les autres
sommets
Suppositions:
On fait grossir un “nuage” de sommets, contenant au départ s et
couvrant éventuellement tous les sommets
Pour chaque sommet v nous emmagasinons d(v) = La plus courte
distance entre v et s dans le sous-graphe constitué du nuage et de ses
sommets adjacents.
0
Le graphe est connexe
Les arêtes sont non-orientées
Les poids des arêtes sont non-négatifs
A
8
8 B
7
2
5
CSI2510 -- PCC
Algorithme de Dijkstra
Considérer une arête
e = (u,z) telle que:
u est le sommet le plus
récemment ajouté au nuage
z n’est pas dans le nuage
Nous mettons à jour les étiquettes des sommets
adjacents à u
0
Dans l’exemple …
8
B
C
3
2
E
∞
1
8
D
B
C
3
2
E
∞
5
∞
7
4
9
F
4
D
9
5
E
F
∞
∞
6
2 1
D
F
s
4
u
d(u) = 50
3 --> chemin
5 plus court!
9
d(u) = 50
d(z) = 75
z
La relaxation d’une arête e
consiste a mettre à jour la
distance d(z) comme suit:
4
2
4
2
2
A
8
0
7
1
Mise à jour = la relaxation des arêtes
Nous ajoutons au nuage le sommet extérieur u qui
a la plus petite étiquette de distance
8
2
Algorithme de Dijkstra
Pour chaque étape:
A
CSI2510 -- PCC
C
3
Exemple
8
4
2
∞
s
u
d(z) = 60
z
d(z) ← min( d(z), d(u) + poids(e) )
5 - chemin plus court! 11 - chemin plus court!
CSI2510 -- PCC
7
CSI2510 -- PCC
8
2
Exemple
Exemple (suite)
0
0
A
8
4
A
8
2
8
C
3
∞
2
2
7
B
0
4
4
1
D
9
E
∞
F
8
B
5
5
E
2
2
7
A
8
2
C
3
3
1
D
7
8
5
F
2
2
7
B
9
4
2
C
3
5
E
3
1
9
D
8
F
5
0
0
A
8
4
A
8
2
8
B
2
5
E
C
3
4
3
1
9
D
11
F
7
7
B
5
2
2
7
5
E
C
3
9
CSI2510 -- PCC
D
8
F
2
5
9
Algorithme de Dijkstra
2
7
B
3
1
4
2
2
2
7
A
8
0
C
3
5
E
3
1
9
D
8
F
5
CSI2510 -- PCC
10
Algorithme de Dijkstra
Algorithm ShortestPath(G, v):
Entrés : Un graphe pondéré G et un sommet particulier v de G.
Sortie : Une étiquette D[u], pour chaque sommet u de G, telle que
D[u] est la longueur d'un plus court chemin de v à u dans G.
Nous emmagasinons les sommets, qui ne sont
pas dans le nuage, dans une file de priorité Q.
initialise D[v] ← 0 et D[u] ← ∞ pour chaque sommet v ≠ u
Soit Q une file à priorité qui contient tous les sommets de G
utilisant les étiquettes de D comme clés.
while Q ≠ ∅ do {tirer u dans le nuage C}
élément: un sommet v
clé: D[v] la distance du sommet
u ← Q.removeMinElement()
pour chaque sommet z adjacent à u tel que z est dans Q faire
{exécuter l'opération de relaxation sur l’arête (u, z) }
Si D[u] + w((u, z)) < D[z] alors
D[z] ←D[u] + w((u, z))
changer la valeur de la clé de z dans Q à D[z]
Retourner l’étiquette D[u] de chaque sommet u.
CSI2510 -- PCC
11
CSI2510 -- PCC
12
3
D
Même exemple, avec un tas
0
8
A
2
B
C
4
D
∞
E
D
∞
F
0
8
2
4
∞
∞
A
B
C
D
E
F
0
A
8
4
(A,D) 4
2
8
2
2
7
B
1
C
3
∞
9
D
RemoveMin()
(A,C) 2
0
5
F
8
B
RemoveMin()
et mise-a-jour
0
A
8
4
4
2
(A,D) 4
(A,B) 8
(A,B) 8
A
8
∞
E
4
2
2
7
5
E
3
3
1
C
9
Relaxation:
D
11
F
(C,D) 3
Mise-a-jour:
5
(C,E) 5 YES (5 < ∞)
(C,F) 11 YES (11 < ∞)
2
8
B
2
2
7
5
E
3
1
C
3
YES (3 < 4)
9
D
11
F
D
(C,B)
au lieu de 4
(C,E) 5
au lieu de
(C,F) 11
au lieu de
NON (9>8)
5
13
CSI2510 -- PCC
0
8
2
4
∞
∞
A
B
C
D
E
F
0
8
2
3
A
B
C
D
∞
∞
E
F
Mise à jour signifie: enlever les anciennes clés
et remplacer par les nouvelles
(A,B) 8
(C,D) 3
au lieu de 4
∞
(C,E) 5
au lieu de
∞
∞
(C,F) 11
au lieu de
∞
Remplacer (A,D) 4 avec (C,D) 3
Insert (C,E) 5
Insert (C,F) 11
Insert (C,E) 5
Insert (C,F) 11
15
(C,D) 3
(A,B) 8
Remplacer (A,D) 4 avec (C,D) 3
CSI2510 -- PCC
14
CSI2510 -- PCC
D
(A,D) 4
Mise à jour signifie: enlever les anciennes clés
et remplacer par les nouvelles
(C,D) 3
9
Quand on doit remplacer, il faut
aussi réarranger le heap
(pas montré dans cet exemple)
CSI2510 -- PCC
16
4
D
0
A
8
B
2
C
3
D
E
Mise à jour signifie: enlever les anciennes clés
et remplacer par les nouvelles
(C,D) 3
Instead of 4
(C,E) 5
Instead of
∞
(C,F) 11
Instead of
∞
D
∞
5
F
(C,E) 5
(C,D) 3
Instead of 4
(C,E) 5
Instead of
∞
(C,F) 11
Instead of
∞
8
2
A
B
C
17
3
D
5
D
F
0
4
2
5
E
3
(C,D) 3
(C,E) 5
18
0
8
2
3
A
B
C
D
5
11
E
F
9
8
D
8
F
B
(A,B) 8
4
2
(C,D) 3
3
1
A
8
2
C
F
0
A
7
11
E
CSI2510 -- PCC
11
E
5
D
(C,F) 11
Insert (C,E) 5
Insert (C,F) 11
0
3
(A,B) 8
Insert (C,E) 5
Insert (C,F) 11
8
2
C
Remplacer (A,D) 4 avec (C,D) 3
D
8
2
B
Remplacer (A,D) 4 avec (C,D) 3
CSI2510 -- PCC
B
8
A
Mise à jour signifie: enlever les anciennes clés
et remplacer par les nouvelles
(C,D) 3
(A,B) 8
0
(C,E) 5
5
2
(C,F) 11
2
7
5
E
C
3
9
D
8
F
(C,E) 5
3
1
(A,B) 8
(C,F) 11
5
RemoveMin()
Mise à jour (D,F) 8 ? Yes 8 < 11
RemoveMin()
Mis-a-jour
Remplacer (C,F) 11
avec (D,F) 8
CSI2510 -- PCC
19
CSI2510 -- PCC
20
5
D
0
8
2
3
A
B
C
D
5
E
Pourquoi l‘algorithme de Dijkstra fonctionne?
8
L’algorithme de Dijkstra utilise un algorithme glouton.
C’est-à-dire un algorithme qui effectue à chaque étape
le choix optimal local dans l’espoir d’arriver à la
solution optimale globale.
F
0
A
8
4
2
8
B
2
2
7
5
E
C
3
9
Supposons qu'il n'a pas trouvé toutes les
plus courtes distances. Soit F le premier
mauvais sommet que l'algorithme a traité.
Quand le nœud précédent, D, sur le vrai
plus court chemin a été considéré, sa
distance était correcte.
Mais l’arête (D,F) a été relaxée à ce
moment-là!
Ainsi, aussi longtemps que d(F)>d(D) la
distance de F ne peut pas être fausse.
C'est-à-dire, il n'y a pas de mauvais
sommet.
D
8
F
(C,E) 5
3
1
(A,B) 8
(D,F) 8
5
RemoveMin()
Mise à jour (D,F) 8 ? Yes 8 < 11
Remplacer (C,F) 11
avec (D,F) 8
CSI2510 -- PCC
21
Le temps d’exécution
4
2
7
2
2
7
B
C
3
5
9
E
3
1
D
8
F
5
22
CSI2510 -- PCC
Le temps d’exécution
Si nous représentons G avec une liste d’adjacence, alors nous pouvons parcourir tous les
sommets adjacents à u pendant un temps proportionnel à deg(u)
La file de priorité Q
Avec heap.
while Q ≠ ∅ do {tirer u dans le nuage C}
A chaque itération:
- Extraction des sommets avec la distance la plus petite: O(log n).
- Mises à jour des clés: O(log n) pour chaque mise à jour (remplacer une clé et insérer
dans le tas)=>Apres chaque extraction (deg(u) mises à jour): O(deg(u) log n)
En total: Σu∈G (1 + deg(u)) log n = O((n+m) log n) = O(m*log n)
Pire cas: O(n2 log n)
CSI2510 -- PCC
0
A
8
Avec une séquence non-triée:
O(n) quand nous extrayons les éléments minimaux
mais des mises à jour des clés plus rapides en O(1).
Il y a seulement n-1 extractions et m mises à jour
Le temps d’exécution est O(n2+m) = O(n2 )
En conclusion:
Séquence
Tas
O(m log n)
23
O(n2 )
CSI2510 -- PCC
24
6