TP 7 : algorithme de Dijkstra

publicité
Université d’Aix-Marseille
Algorithmique
L2 Informatique - Mathématiques 2016/2017
TP 7 : algorithme de Dijkstra
Ce TP est consacré à la programmation de l’algorithme de Dijkstra.
On enregistre un graphe orienté pondéré sous forme d’un fichier ASCII dont
— la première ligne contient le nombre de sommets du graphe
— la seconde ligne contient le nombre d’arcs du graphe
— chaque ligne suivante décrit un arc sour la forme : sommet1, sommet2, poids
Dessinez le graphe correspondant au fichier suivant.
6
10
0 1
0 2
1 2
1 4
2 3
2 4
3 1
3 4
3 5
4 5
19
8
14
6
4
22
2
10
11
2
— Un graphe sera représenté par un type structuré comprenant deux champs :
— nbSommets : le nombre de sommets du graphe
— Adj : les listes d’adjacence du graphe.
— Adj est un tableau d’éléments de type LISTE, où LISTE décrit des listes chaı̂nées de
couples (sommet,poids) ; Adj[v] est la liste des sommets adjacents au sommet v ;
seules les nbSommets premières cases de Adj sont pertinentes pour le graphe.
— La fonction void litGraphe(char *adr, GRAPHE *G) saisit un graphe à partir d’un
fichier.
#define POIDS_MAX 50 // poids maximum
#define NB_SOM_MAX 10 // nombre de sommets maximum
/* liste cha^
ınée de couples (sommet, poids) */
typedef struct maillon{
struct maillon *suiv;
int nom;
int poids;
} MAILLON, *LISTE;
1
/* structure de graphe */
typedef struct graphe{
int nbSommets;
LISTE Adj[NB_SOM_MAX]; // liste d’adjacence
} GRAPHE;
/* pour charger un graphe à partir d’un fichier */
void litGraphe(char *adr, GRAPHE *G){
FILE *f;
int sa,sb,pds,nbArcs;
f=fopen(adr,"r");
fscanf(f,"%d",&(G->nbSommets));
initAdjGraphe(G); // à écrire
fscanf(f,"%d",&nbArcs);
while (nbArcs){
fscanf(f,"%d %d %d",&sa,&sb,&pds);
insere(sa,sb,pds, G->Adj); // à écrire
nbArcs--;
}
fclose(f);
}
On pourra utiliser la fonction main suivante :
int main(void){
GRAPHE G;
litGraphe("./graphe.txt", &G);
afficheGraphe(G);
dijkstra(0, G);
return 0;
}
Écrivez les fonctions suivantes :
1. /* insère (som_b,poids) en t^
ete dans la liste d’adjacence Adj[som_a] */
void insere(int som_a,int som_b, int poids, LISTE Adj[]){ ... }
2. /* initialisation de la table d’adjacence : toutes les listes cha^
ınées
sont vides */
void initAdjGraphe(GRAPHE *G){ ... }
3. /* affichage d’un graphe : le nombre de sommets, puis
chaque arc pondéré : (sommet_1, sommet_2, poids) */
void afficheGraphe(GRAPHE G){ ... }
4. /* algorithme de Dijkstra : calcule (et affiche) les tableaux dist et pred */
void dijkstra(int s, GRAPHE G){...}
Dans un premier temps, vous pourrez implémenter l’ensemble F des sommets à explorer comme un tableau de G.nbSommets éléments tels que F [i] = 1 si le sommet i est
dans F et F [i] = 0 sinon.
2
5. Complétez l’algorithme précédent pour qu’il affiche les chemins les plus courts entre
s et tous les sommets de G (du coup, on n’aura plus besoin qu’il affiche les tableaux
dist et pred. Pour cela, vous pourrez aussi écrire des fonctions
— int affiche plus court chemin(int s, int t, int pred[]) qui affiche le plus
court chemin de s à t et renvoie 0 s’il n’existe pas, et
— void affiche plus courts chemins(int s, int nbSommets, int pred[], int
dist[]) qui affiche tous les plus courts chemins à partir de s, avec leur distance.
Plus
Plus
Plus
Plus
Plus
Plus
court
court
court
court
court
court
chemin
chemin
chemin
chemin
chemin
chemin
de
de
de
de
de
de
2
2
2
2
2
2
à
à
à
à
à
à
0
1
2
3
4
5
:
:
:
:
:
:
sommet non atteint.
2 3 1 . Distance : 6
2 . Distance : 0
2 3 . Distance : 4
2 3 1 4 . Distance : 12
2 3 1 4 5 . Distance : 14
6. (difficile) Si l’on implémente F comme un tableau, la recherche du sommet i pour
lequel dist[i] est minimale est linéaire : d’où une complexité de O(n2 ) au total,
où n =G.nbSommets. Si l’on implémente F comme une file de priorité, c’est-à-dire
un tasmin muni d’une fonctionnalité de mise à jour, on obtient une complexité de
O(n log n). Écrivez cette variante de l’algorithme de Dijkstra : void dijkstraFP(int
s, GRAPHE G). Pour cela,
— vous introduirez les variables int f[NB SOM MAX], nf, ind f[NB SOM MAX], où f
représente le tasmin prioritarisé par dist 1 , nf est le nombre d’éléments du tasmin
et ind f[i] donne l’indice du sommet i dans le tasmin f ;
— la fonction int extrait min(int f[], int ind f[], int *nf, int dist[]) extrait le min de f, c’est-à-dire f[0], tout en préservant la structure de tasmin et en
actualisant ind f
— la fonction void maintient(int f[], int ind f[], int i, int dist[]) qui
maintient la structure de f et la sémantique de ind f lorsque dist[i] a été diminué
pour un sommet i de f.
7. (difficile) La structure que nous avons considérée pour les listes d’adjacence est midynamique (les listes d’adjacences elles-mêmes), mi-statique (on déclare un tableau de
NB SOM MAX listes d’adjacence). Comment faire en sorte que la structure soit totalement
dynamique, c’est-à-dire ne dépende pas de la constante NB SOM MAX ?
1. si i est un ascendant de j, alors dist[i]dist[j].
3
Téléchargement