TP 5 : Graphes pondérés

publicité
MP*
Lycée Masséna
TP 5 : Graphes pondérés
Télécharger le fichier sur le site web contenant des fonctions et quelques exemples de graphes.
1
Implémentation de l’algorithme de Floyd-Warshall
Question 1. Implémentez l’algorithme de Floyd Warshall, rappelé ci-dessous. On utilisera pour cela le type zbar.
#floyd_warshall g1 ;;
- : zbar vect vect =
[|[|Z 0; Z 1; Z -3; Z 2; Z -4|]; [|Z 3; Z 0; Z -4; Z 1; Z -1|];
[|Z 7; Z 4; Z 0; Z 5; Z 3|]; [|Z 2; Z -1; Z -5; Z 0; Z -2|];
[|Z 8; Z 5; Z 1; Z 6; Z 0|]|]
#floyd_warshall gneg ;;
- : zbar vect vect =
[|[|Z -1; Z 1; Z -2; Inf; Inf|]; [|Z -3; Z -1; Z -4; Inf; Inf|];
[|Z -1; Z 1; Z -2; Inf; Inf|]; [|Z 1; Z 3; Z 0; Z 0; Z 5|];
[|Z -3; Z -1; Z -4; Inf; Z 0|]|]
Algorithme 1 : Algorithme de Floyd-Warshall
Entrée : Un graphe pondéré G = (V, E, ω) donné par sa matrice d’adjacence M
Sortie : La matrice des plus courtes (δ(i, j))0≤i,j<n distances entre deux sommets quelconques du graphe
A ← copie(M );
pour tout k entre 0 et n − 1 faire faire
pour tout i entre 0 et n − 1 faire faire
pour tout j entre 0 et n − 1 faire faire
ai,j ← min(ai,j , ai,k + ak,j )
Renvoyer A
−5
1
4
2
3
7
3
8
1
0
6
4
-4
2
Figure 1: Le graphe du cours (graphe g1)
Question 2. Modifiez l’algorithme pour tester l’existence d’un circuit de poids total strictement négatif.
#floyd_warshall gneg ;;
Uncaught exception: Failure "cycle de poids strictement negatif"
Question 3. Modifier l’algorithme pour calculer en même temps la matrice de liaison Π = (πi,j )0≤i,j<n , définie par :
le prédecesseur de j dans un plus court chemin de i à j, s’il en existe un
πi,j =
−1 sinon (on pourrait mettre autre chose)
Svartz
Page 1/4
2015/2016
MP*
Lycée Masséna
#floyd_warshall g1 ;;
- : zbar vect vect * int vect vect =
[|[|Z 0; Z 1; Z -3; Z 2; Z -4|]; [|Z 3; Z 0; Z -4; Z 1; Z -1|];
[|Z 7; Z 4; Z 0; Z 5; Z 3|]; [|Z 2; Z -1; Z -5; Z 0; Z -2|];
[|Z 8; Z 5; Z 1; Z 6; Z 0|]|],
[|[|0; 2; 3; 4; 0|]; [|3; 1; 3; 1; 0|]; [|3; 2; 2; 1; 0|];
[|3; 2; 3; 3; 0|]; [|3; 2; 3; 4; 4|]|]
Question 4. Écrire une fonction impression pi i j d’impression à l’écran d’un plus court chemin entre i et j s’il
en existe un.
#imprimer_chemin pi 0 1 ;;
0 4 3 2 1
- : unit = ()
Question 5. Pour G = (V, E) un graphe (non pondéré), on appelle fermeture transitive de G le graphe Gf = (V, Ef )
avec (i, j) ∈ Ef si et seulement si il existe un chemin de i à j dans G. Écrire un algorithme capable de calculer la
fermeture transitive d’un graphe avec un algorithme inspiré de l’algorithme de Floyd-Warshall, mais travaillant sur
des matrices de booléens.
#warshall g2 ;;
- : int vect vect =
[|[|0; 1; 1; 0; 0;
[|0; 0; 1; 0; 0;
[|0; 0; 0; 0; 0;
[|1; 1; 1; 0; 1;
[|1; 1; 1; 1; 0;
[|0; 1; 1; 0; 0;
[|0; 1; 1; 0; 0;
[|0; 0; 1; 0; 0;
[|0; 0; 1; 0; 0;
[|0; 0; 0; 0; 0;
[|0; 1; 1; 0; 0;
[|0; 1; 1; 0; 0;
[|0; 0; 0; 0; 0;
[|0; 0; 0; 0; 0;
2
1;
1;
0;
1;
1;
0;
1;
0;
0;
0;
1;
1;
0;
0;
1;
1;
0;
1;
1;
1;
0;
0;
0;
0;
1;
1;
0;
0;
1;
1;
0;
1;
1;
1;
1;
0;
0;
0;
1;
1;
0;
0;
1;
1;
1;
1;
1;
1;
1;
1;
0;
0;
1;
1;
0;
0;
0;
0;
0;
1;
1;
0;
0;
0;
0;
0;
0;
0;
0;
0;
1;
1;
0;
1;
1;
1;
1;
0;
0;
0;
0;
1;
0;
0;
1;
1;
0;
1;
1;
1;
1;
0;
0;
0;
1;
0;
0;
0;
1;
1;
0;
1;
1;
1;
1;
0;
0;
0;
1;
1;
0;
1;
1|];
1|];
0|];
1|];
1|];
1|];
1|];
0|];
0|];
0|];
1|];
1|];
1|];
0|]|]
Implémentation de l’algorithme de Dijkstra
Les graphes sous représentations creuses sont donnés sous le type (int * int) list vect, un couple (u, ω) dans
la liste d’adjacence d’un somme t signifie qu’il y a un arc (t, u) dans le graphe, de poids ω.
Algorithme 2 : Algorithme de Dijkstra
Entrée : Un graphe pondéré G = (V, E, ω) donné par listes d’adjacences, avec ω(E) ⊂ R+ , un sommet s
Sortie : Les distances δ(s, t) pour tout t ∈ V
d[t] ← +∞ pour tout t ∈ V ; d[s] ← 0;
E ← ∅ ; F ← {s};
tant que F 6= ∅ faire
u ← Retirer de F un sommet v vérifiant d[v] minimal parmi les sommets de F ;
pour tout voisin v de u faire
si v n’est ni dans F ni dans E alors
Ajouter v à F
d[v] ← min(d[v], d[u] + ω(u, v))
Ajouter u à E
Renvoyer d
Vous trouverez sur le site web une implémentation des files de priorité spécialement adaptée à l’algorithme de
Dijkstra. Le type associé est le suivant :
type fp_min = {tas: (int * int) vect ; indice: int vect ; mutable nb: int } ;;
Svartz
Page 2/4
2015/2016
MP*
Lycée Masséna
Les fonctions sont les suivantes :
— creer_fp : int -> fp_min : prend en paramètre un entier n, et retourne une file de priorité min de capacité
n, vide.
— est_vide_fp : fp_min -> bool
— inserer : fp_min -> int -> int -> unit : l’appel inserer f t dt rajoute le sommet t, supposé non présent, à la file de priorité, avec priorité dt.
— diminuer_cle : fp_min -> int -> int -> unit : l’appel diminuer_cle f t dt diminue la clé du sommet
t, supposé présent.
— retirer_min : fp_min -> int * int : retire le minimum de la file de priorité (i.e renvoie (t, dt ) avec dt
minimal).
Exceptée la création, toutes ces fonctions s’exécutent en temps constant, sauf les opérations classiques de files de priorité
qui s’exécutent en temps O(log n)) (n étant la capacité de la file). Remarquez l’utilisation d’un vecteur indice : à
tout moment indice.(v) contient l’indice dans le tas du couple associé au nœud v (s’il est dans la file). Ceci est
transparent pour l’utilisateur.
0
1
0
10
2
5
7
3
4
9
2
4
2
6
3
Figure 2: Un graphe pondéré à poids positifs (g3)
Question 6. Implémentez l’algorithme de Dijkstra. La fonction dijkstra g s doit renvoyer un tableau de distances
de type int vect contenant les distances entre s et tous les nœuds accessibles du graphe, et −1 pour les non accessibles.
(Comme les poids sont positifs, il n’y a pas ambiguïté).
# dijkstra g3 0;;
- : int vect * int vect = [|0; 8; 9; 7; 5|], [|0; 4; 1; 4; 0|]
#dijkstra g4 0 ;;
- : int vect * int vect = [|0; 5; 1; 8; 3; 6|], [|0; 4; 0; 4; 2; 1|]
#dijkstra g4 3 ;;
- : int vect * int vect =
[|-1; -1; -1; 0; -1; -1|], [|-1; -1; -1; 3; -1; -1|]
Question 7. Rajouter la production d’un tableau de prédecesseurs, comme ci-dessus.
Question 8. Profitez ensuite de l’implémentation pour réviser la structure de file de priorité.
3
Project-Euler 83
Dans la matrice ci-dessous, la somme minimale d’un chemin entre le coin en haut à gauche et le coin en bas à droite
est 2297. Un trajet correspondant est indiqué en gras (naturellement, on ne peut se déplacer qu’horizontalement et
verticalement, pas en diagonale).
131
201
630
537
805
Svartz
673
96
803
699
732
234
342
746
497
524
103
965
422
121
37
Page 3/4
18
150
111
956
331
2015/2016
MP*
Lycée Masséna
Sur mon site web, vous trouverez une matrice au format ml de taille 80 × 80. Déterminez la somme minimale d’un
chemin entre le coin en haut à gauche et le coin en bas à droite, et résolvez ainsi le problème 83 du site Project-Euler.
Indication : écrire une fonction permettant de construire le graphe associé à une matrice à coefficients positifs (il est
très creux !), et lancez Dijkstra depuis 0. Ne pas oublier de rajouter le coefficient en haut à gauche à votre longueur
de chemin.
Vous pouvez aussi résoudre les problèmes 81 et 82. Ils sont en fait plus simples et une solution basée sur la
programmation dynamique est possible, ce qui évite le recours aux graphes. C’est un bon exercice de révision.
Svartz
Page 4/4
2015/2016
Téléchargement