TD n 4 - Correction

publicité
Université Paris Diderot – Paris 7
L3 Informatique
Algorithmique
Année 2009-2010, 1er semestre
TD n◦4 - Correction
Parcours de graphes
Exercice 1 Y’a qu’à...
Exercice 2 Non ! Par exemple, le graphe de sommets {a, b, c, d, e} et d’arêtes {(ab), (ac), (bd), (be), (cd), (ce)}.
L’arbre d’arêtes {(ab), (ac), (bd), (ce)} ne peut pas être obtenu par un parcours en largeur, mais est bien
un arbre de plus courts chemins partant de a.
Exercice 3 Y’a qu’à...
Exercice 4
Le premier problème est qu’on fait un parcours sans relance. Ainsi s’il y a un circuit inaccessible depuis
le sommet de départ, on ne le détectera pas.
Un problème plus sérieux est illustré en faisant tourner l’algorithme sur le graphe de la figure 1. Vous avez
vu en cours qu’un arc retour dans un parcours en profondeur permet de détecter un cycle. L’algorithme
proposé ici n’utilise que deux couleurs pour marquer les noeuds, ainsi un arc transverse ou un arc avant
peut être pris pour un arc de retour et signaler un faux circuit.
Fig. 1 – Un graphe dirigé
Une solution pourrait être de modifier l’algorithme pour distinguer les arcs retour des arcs transverses et
en avant. Mais, est-ce suffisant ? Est-ce que notre parcours en profondeur va systématiquement rencontrer
un arc retour si le graphe contient un cycle ? Oui, mais pour cela il faut démontrer le théorème suivant.
Théorème 1 Dans un graphe orienté il existe un circuit si et seulement si dans chaque parcours en
profondeur il existe un arc de retour.
Ainsi, si un parcours en profondeur ne trouve pas d’arc retour, c’est effectivement qu’il n’y a pas de
circuit.
1
L’algorithme correct est alors :
1
2
3
4
5
Procédure Cherche_Circuit(G)
// G = (S, A) graphe orienté
pour chaque s ∈ S faire
Marquage[s] := blanc ;
Père[s] := nil ;
7
pour chaque s ∈ S faire
si CC(G,s) alors terminer
8
afficher("pas de circuit") ;
6
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Fonction CC(G, s)
// G = (S, A) graphe orienté
Marquage[s] := gris ;
pour chaque x ∈ Voisinage(s,G) faire
si Marquage[x] == blanc alors
Père[x] := s ;
si CC(G, x) alors renvoyer vrai ;
sinon
si Marquage[x] == gris alors
afficher(x) ;
y := s ;
tant que y 6= x faire
afficher(y) ;
y := Père[y] ;
renvoyer vrai;
24
25
26
Marquage[s] := noir ;
renvoyer faux;
Cet algorithme se termine pour les mêmes raisons que l’algorithme de parcours en profondeur avec la
même complexité.
Preuve du théorème. L’implication (⇐) a été montré en cours : s’il y a un arc de retour (x, y) alors
le chemin de y vers x dans l’arbre de parcours et l’arc (x, y) forment le circuit.
Pour montrer la réciproque (⇒), supposons qu’il existe un circuit C dans G et nommons v le premier
sommet de ce circuit qui est visité pendant le parcours en profondeur. Nommons p le prédécésseur de v
sur ce circuit. En utilisant la notion de date de début et de date de fin utilisée dans le cours1 , à l’instant
début[v], tous les sommets du circuit sont blancs, ou autrement dit, pour chaque sommet x du circuit
différent de v : début[v] < début[x]. Il suffit alors de montrer qu’à l’instant f in[p] le sommet V est encore
gris. Autrement dit, il suffit de montrer f in[p] < f in[v].
Par la propriété des intervalles de traitement2 et l’inégalité précédente, chacun des sommets x de C est
dans un des deux cas suivants :
1. soit début[v] < début[x] < f in[x] < f in[v]
2. soit début[v] < f in[v] < début[x] < f in[x]
Si le sommet p est dans le cas 1 le résultat est immédiat.
Si ce sommet est dans le cas 2, montrons qu’il y a une contradiction. En effet, cela signifirait que le
sommet p qui est accessible depuis v n’a pas été visité à la fin de l’exploration de v, ce qui est contraire
à l’intuition du parcours en profondeur.
1 rappel
2 voir
: début et f in donnent les dates du début et de la fin de traitement des sommets
cours
2
Plus précisement, examinons la situation à l’instant f in[v]. À cet instant d’après la propriété des intervalles, un sommet x du circuit C est soit noir (cas 1), soit blanc (cas 2). Par hypothèse, p est blanc,
et considérons le premier prédecesseur de p sur C qui soit noir (ce prédécesseur existe, car v est noir),
nommons le s. Le successeur de s sur C est blanc. Or, on vérifie aisément sur la définition de l’algorithme,
qu’à tout instant le successeur d’un noeud noir est noir. Le successeur de s sur C ne peut être blanc et
noir à la fois. Contradiction.
Exercice 5 On fait une modification du parcours en largeur. En effet, il trouve des plus courts chemins,
donc il y a lieu d’espérer qu’il trouve aussi des plus courts circuits. Cet algorithme est suivi d’une preuve
pour se convaincre de cette affirmation.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Procédure Cherche_Circuit(G, s)
// G = (S, A) graphe orienté
pour chaque x ∈ S faire
Marquage[x] := faux ;
Père[x] := nil ;
F := File_Vide ;
Enfiler(s,F) ;
Marquage[s] := vrai ;
Profondeur[s] := 0 ;
tant que F non vide faire
x := Defiler(F) ;
pour chaque y ∈ Voisinage(x, G) faire
si non(Marquage[y]) alors
Enfiler(y,F) ;
Marquage[y] := vrai ;
Père[y] := x ;
Profondeur[y] := Profondeur[x] + 1;
sinon
si y = s alors
tant que x 6= nil faire
afficher(x) ;
x := Père[x] ;
renvoyer vrai ;
Preuve :
– Terminaison. On étudie les exécutions possibles de l’algorithme. Si une exécution entre dans le sinon
de la ligne 18, alors l’algorithme termine (en renvoyant vrai). Si au contraire elle n’entre jamais dans
ce sinon, alors elle se déroule exactement comme un parcours en profondeur, et donc termine aussi. On
conclut que l’algorithme termine.
– Preuve que l’algorithme trouvera un circuit s’il y en a un passant par s. On suppose qu’il
existe au moins un circuit passant par s. On considère, parmi les circuits de longueur minimale passant
par s, les sommets de plus grande profondeur en partant de s. Parmi ceux-là, l’un d’eux sera le premier
atteint par le parcours en largeur effectué par l’algorithme. Pour ce sommet, on entre dans le sinon de
la ligne 18, et l’algorithme renvoie vrai.
Jusqu’à ce qu’on entre dans le sinon de la ligne 18, les invariants du cours sur le parcours en largeur
sont vérifiés. En particulier, les sommets dont la distance depuis s est strictement inférieure ont déjà
été visités, et l’arbre obtenu est un arbre des plus courts chemins depuis s.
– Minimalité d’un circuit trouvé Ainsi, au moment où on rentre dans le sinon, on trouve donc un
circuit sur s. Et on sait que tout sommet x dont la distance à s est strictement inférieure a été visité
précédemment. Puisqu’on n’est entré dans le sinon de la ligne 18 à la visite de x, c’est que x n’est pas
lié a s. On en déduit que le cycle passant par s trouvé par l’algorithme est de longueur minimale.
3
Exercice 6 Tout graphe non orienté et connexe G vérifie une et une seule des conditions suivantes :
– soit G est un arbre,
– soit G contient un cycle.
Or d’après le cours, un graphe non orienté connexe G = (S, A) est un arbre si et seulement si |A| = |S|−1.
Pour tester si un tel graphe possède un cycle, il suffit donc de tester si |A| > |S| − 1. Cet algorithme ne
permet cependant pas d’exhiber un cycle dans le graphe.
Exercice 7 Un pseudo-code possible du parcours en profondeur avec relance. On n’utilise pas de
marques : les dates remplacent. Un début à -1 signifie un sommet non encore atteint, un début ≥ 0
mais une fin de -1 signifie un sommet en cours de visite.
Variables globales: sommet x,y; entier temps = 0, d[V], f[V] tableaux initialises à -1
Pour x de 1 a n
Si marquage[x] = faux
PP(x)
Procedure PP(sommet v)
d[v] = temps++
pour chaque voisin
si d[y] == -1
Afficher
PP(y)
sinon si f[v]
Afficher
sinon si f[y]
Afficher
sinon
Afficher
f[v] = temps++
y de v faire
(v,y) est un arc de parcours
== -1
(v,y) est un arc de retour (aussi appelé en arrière)
< d[v]
(v,y) est un arc transversal
(v,y) est un arc en avant
4
Téléchargement