Parcours de graphes - Option informatique MPSI/MP/MP

publicité
Lycée Carnot — 2016-2017
Option informatique MP/MP*
TP 3 : Parcours de graphes et applications
Dans ce TP, on étudie deux différents parcours de graphes à l’aide d’une interface générique, et quelquesunes de leurs applications : recherche des composantes connexes, tri topologique d’un graphe et détection
de cycles dans un graphe.
Pour traiter ce TP, il faut avoir fini les parties 2 et 3 du TP no 2, puisque nous utiliserons vos implémentations de graphe.
1
Piles et files
On rappelle l’interface générique d’une file ou d’une pile que vous avez implémentées au TP no 1.
type ’a t;;
exception Empty;;
exception Full;;
value
value
value
value
value
empty : unit -> ’a t;;
is_empty : ’a t -> bool;;
is_full : ’a t -> bool;;
push : ’a -> ’a t -> unit;;
pop : ’a t -> ’a ;;
Si votre implémentation est douteuse, vous pouvez utiliser les modules C AML stack et queue, par
exemple :
let p = stack__new ();;
stack__push 33 p;;
stack__pop p;;
let is_empty p = stack__length p = 0;;
Attention : l’interface est légèrement différente de celle que l’on a vue en cours (et différente pour les
piles et files). Le cas des files et piles vides est géré à l’aide d’une exception. Lisez bien la documentation
des deux modules : http://caml.inria.fr/pub/docs/manual-caml-light/node15.html.
2
Parcours d’un graphe
Q UESTION 1 Le pseudo-code du parcours en profondeur est donné par les algorithmes 1 et 2. Faire tourner
ces deux algorithmes à la main sur quelques exemples simples pour être sûr de bien comprendre.
Q UESTION 2 On considère tout d’abord que postvisiter ne fait rien et que previsiter s imprime à
l’écran le sommet s (ici un entier). Implémenter les deux algorithmes en C AML. Vérifier que votre implémentation est bien indépendante de l’implémentation de graphe sous-jacente (cela doit fonctionner aussi
bien avec une représentation par matrice d’adjacence ou par listes d’adjacence), que le graphe soit orienté
ou non. Essayer sur plusieurs exemples.
Q UESTION 3 Que se passe-t-il si on inverse les rôles de previsiter et postvisiter dans la question
précédente ?
Q UESTION 4 Comment obtenir en sortie la liste de tous les sommets dans l’ordre de leur première visite ?
Implémenter cela en C AML.
Q UESTION 5
exemples.
Remplacer la pile par une file pour obtenir un parcours en largeur et le vérifier sur des
http://carnot.cpge.info
1
Lycée Carnot — 2016-2017
Option informatique MP/MP*
Algorithme 1 : explorer(G, s) : exploration en profondeur à partir d’un sommet.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Entrée : Graphe G = (S, A), sommet s ∈ S
pile ← creer_pile_vide();
empiler(s, pile);
tant que pile est non vide faire
t ← depiler(pile);
si t est marqué alors
si t pas encore postvisité alors
postvisiter(t);
fin
fin
sinon
prévisiter(t);
marquer t;
empiler(t, pile);
pour tout voisin u de t faire
si u n’est pas marqué alors
empiler(u, pile);
fin
fin
fin
fin
Algorithme 2 : parcours_pronfondeur(G) : parcours en profondeur d’un graphe.
1
2
3
4
5
3
Entrée : Graphe G = (S, A)
pour s dans S faire
si s n’est pas marqué alors
explorer(G, s);
fin
fin
Temps de premier et dernier passage
Dans tout ce qui va suivre, on s’intéresse au parcours en profondeur, celui obtenu à l’aide d’une pile.
Q UESTION 6 On considère une variable horloge initialisée à 0, qui est incrémentée à chaque fois que l’on
prévisite ou que l’on postvisite un sommet. On utilise également deux tableaux pre et post, dans lesquels
on met à jour pour chaque sommet son heure de prévisite (appelée aussi temps de premier passage) et
de postvisite (temps de dernier passage). Pour s, s0 ∈ S, montrer que soit les intervalles [ pre[s], post[s]] et
[ pre[s0 ], post[s0 ]] sont disjoints, soit l’un est inclus dans l’autre. Que réprésente l’intervalle [ pre[s], post[s]] ?
Implémenter cela en C AML et essayer sur quelques exemples.
4
Composantes connexes d’un graphe non-orienté
Q UESTION 7 On veut modifier l’algorithme pour obtenir les composantes connexes, sous la forme d’un
tableau composantes où composantes[s] est l’identifiant (un entier unique pour chaque composante)
de la composante connexe à laquelle appartient s. On va donc définir
let previsiter s composantes id =
composantes.(s) <- !id
;;
http://carnot.cpge.info
2
Lycée Carnot — 2016-2017
Option informatique MP/MP*
À quel endroit faut-il incrémenter la référence id pour que le parcours permette de calculer les composantes connexes ?
Q UESTION 8 Écrire une fonction is_connected : graph -> bool qui vérifie si un graphe est connexe.
Q UESTION 9 Écrire une fonction connected_components : graph -> graph list qui renvoie les
sous-graphes correspondant aux composantes connexes.
5
Graphes orientés acycliques et tri topologique
Définition 1. Un ordre topologique d’un graphe orienté G = (S, A) est un ordre total 2 sur les sommets tel que
si (s, s0 ) ∈ A alors s ≺ s0 , c’est-à-dire compatible avec la relation d’ordre partielle donnée par les arcs.
Q UESTION 10 Montrer qu’un graphe orienté qui admet un ordre topologique est acyclique.
Q UESTION 11 Montrer que dans un graphe orienté acyclique G = (S, A), si (s, s0 ) ∈ A alors post[s] >
post[s0 ].
Q UESTION 12 En déduire un algorithme qui détecte si un graphe est acyclique et l’implémenter.
Q UESTION 13 À l’aide des temps de dernier passage, trouver un algorithme qui, pour un graphe acyclique,
trie les sommets de ce graphe selon un ordre topologique et l’implémenter.
Remarque 1. Il y a donc équivalence, pour un graphe orienté, entre être acyclique et admettre un ordre topologique.
6
Composantes fortement connexes d’un graphe orienté
Soit G = (S, A) un graphe orienté.
Q UESTION 14 Pourquoi ne peut-on pas simplement effectuer un parcours de graphe pour trouver les
composantes (fortement) connexes, comme dans le cas non-orienté ?
On définit le méta-graphe de G comme étant le graphe MG = (C f , A f ) où C f est l’ensemble des composantes fortement connexes de G et A f = {(c1 , c2 ) ∈ C2f , ∃s1 ∈ c1 , ∃s2 ∈ c2 , (s1 , s2 ) ∈ A}.
Q UESTION 15 Montrer que MG est un graphe orienté acyclique. À quelle condition a-t-on G = MG ?
Q UESTION 16 Soit c ∈ C f tel que d+ (c) = 0, on dit que c est un puits. Soit s ∈ c. Pourquoi la fonction
explorer au départ de s dans G permet de trouver exactement c ? Ceci suggère un algorithme pour
trouver les composantes fortement connexes : (1) choisir un sommet s appartenant à un puits de MG ;
(2) utiliser le parcours en profondeur à partir de sommet pour construire sa composante connexe ; (3)
supprimer cette composante du graphe initial ; (4) recommencer avec les sommets restants.
Le problème, c’est que l’on ne voit pas bien a priori comment trouver un sommet appartenant à un
puits de MG . En revanche, il est plus simple de trouver un sommet appartenant à une source de MG . Un
sommet c est une source si d− (c) = 0.
Q UESTION 17 Soient c1 , c2 ∈ C f , montrer que si (c1 , c2 ) ∈ A f alors
max post[s1 ] > max post[s2 ]
s1 ∈ c1
s2 ∈ c2
En déduire un algorithme permettant de trouver un sommet s appartenant à une source de M f .
Q UESTION 18 Pour trouver un puits de MG , on peut utiliser le graphe transposé de G (cf. E XERCICE 15 du
TP no 2). Pourquoi les composantes fortement connexes de G R sont les mêmes que celles de G ? Que vaut
M f ( G R ) ? En déduire un algorithme pour trouver un sommet s appartenant à un puits de M f ( G ).
Q UESTION 19 En déduire un algorithme pour trouver les composantes fortement connexes d’un graphe
oriente et l’implémenter en C AML. Montrer que sa complexité est toujours linéaire (i.e. O(|S| + | A|)).
http://carnot.cpge.info
3
Téléchargement