#include #include #include #define ng1 n #if 1 #define n 1001 // nombre de sommets du graphe #define a 835 // nombre d'arcs du graphe #define initg2 initg2_23(g2) typedef short int sommet; // Les numéros de sommet sont des entiers codés sur 16 bits. sommet depart=7, arrivee=1; #elif 0 #define n 100000 #define a 103333 #undef ng1 #define ng1 1 #define initg2 initg2_352(g2,poids) typedef int sommet; // Les numéros de sommet sont des entiers codés sur 32 bits. sommet depart=10001, arrivee=10000; #else #define n 4 #define a 8 #define initg2 typedef short int sommet; sommet depart=1, arrivee=0; #endif typedef char bool; // les booléens, qui valent 0 ou 1 seront des entiers sur un octet. typedef bool graphe1[ng1][ng1];// Un graphe1 est une matrice nxn de booléens. g1[i][j] ssi i-->j est un arc typedef struct {sommet ori, ext;} graphe2[a]; // Un graphe2 est un tableau de a arcs. Les arc sont g2[k].ori-->g2[k].ext typedef int tetesuite[n+a]; // int tete[n], suite[a]; avec suite=tete+n // Les arcs partants de i sont tete[i], suite[tete[i]], suite[suite[tete[i]]], ... typedef struct chainon *liste; // Une liste est un pointeur sur un chaînon struct chainon {sommet s; liste suite;}; // qui contient un sommet et le pointeur sur le chaînon suivant. typedef liste graphe3[n]; // Un graphe3 est un tableau de n listes chaînées de sommets. // Les successeurs du sommet i sont g3[i]->s, g3[i]->suite->s, g3[i]->suite->suite->s, ... // // Affichage des graphes pour chacune des trois représentations. // void affg1(graphe1 g) { sommet i,j; // pour tout couple de sommets (i,j) si g[i][j], c'est-à-dire si i-->j est un arc, on l'affiche for(i=0;i%d ", i, j); printf("\n"); } void affg2(graphe2 g) { int k; // pour tout k de 0 à a-1 on affiche le kième arc g[k].ori-->g[k].ext for(k=0;k%d ", g[k].ori, g[k].ext); printf("\n"); } void affg3(graphe3 g) { sommet i; // pour chaque sommet i, p décrit la liste des arcs partant de i, ce qui permet d'afficher l'arc i-->p->s liste p; for(i=0;isuite) printf("%d-->%d ", i, p->s); printf("\n"); } // // Conversion entre les trois représentations de graphes // void g1g2(graphe1 g1, graphe2 g2) // remplit g2 à partir de g1 { sommet i,j; // pour tout couple de sommets (i,j) si g[i][j], c'est-à-dire si i-->j est un arc, on l'ajoute dans g2 int k=0; for(i=0;ij dans g1[i][j] on remplace le 0 par un 1. } void g1g3(graphe1 g1, graphe3 g3) // remplit g3 à partir de g1 { sommet i,j; for(i=0;ij { liste p=malloc(sizeof(*p)); // p est un nouveau chaînon p->s=j; // contenant le sommet j p->suite=g3[i], g3[i]=p; // que l'on rajoute en tête de la liste des arcs partant du sommet i } } void g3g1(graphe3 g3, graphe1 g1) // remplit g1 à partir de g3 { sommet i,j; liste p; for(i=0;isuite) g1[i][p->s]=1; // Pour chaque arc i-->j dans g1[i][j] on remplace le 0 par un 1. } void g3g2(graphe3 g3, graphe2 g2) // remplit g2 à partir de g3 { sommet i; // pour chaque sommet i, p décrit la liste des arcs partant de i, ce qui permet d'ajoute l'arc i-->p->s dans g2 int k=0; liste p; for(i=0;isuite) g2[k].ori=i, g2[k++].ext=p->s; } void g2g3(graphe2 g2, graphe3 g3) // remplit g3 à partir de g2 { int k; sommet i; for(i=0;ij (en fait i=g2[k].ori et j=g2[k].ext) { liste p=malloc(sizeof(*p)); // p est un nouveau chaînon p->s=g2[k].ext; // contenant le sommet j p->suite=g3[i=g2[k].ori]; // que l'on rajoute en tête de la liste des arcs partant du sommet i g3[i]=p; } } // // Chaînage des arcs partant d'un même sommet pour la représentation graphe2 // void g2ts(graphe2 g2, tetesuite tete) // remplit tete et suite à partir de g2 { int k, *suite=tete+n; // les deux tableaux int tete[n], suite[a]; sont consécutifs en mémoire et forment donc un seul tableau de taille n+a sommet i; for(i=0;isuite) // chaque de successeur de s dfs3(p->s,g,visite); // est visité } } void dfs2(sommet s,graphe2 g,tetesuite tete,bool visite[n]) { if(!visite[s]) // Si le sommet s n'a pas encore été visité { int k, *suite=tete+n; visite[s]=1; // on note que maintenant il a été visité puis for(k=tete[s];k>=0;k=suite[k]) // pour chaque arc k partant de s dfs2(g[k].ext,g,tete,visite); // on visite son extrémité } } // // Retournement du sens des arcs pour chacune des trois représentations des graphes // void retg1(graphe1 g) // change le sens du graphe : l'arc i-->j devient l'arc j-->i { int i,j; for(i=0;ij for(j=0;jj, les deux variables g[1][2] et g[2][1] seront échangées deux fois, } // pour (i,j)=(1,2) et (i,j)=(2,1), et elles reprendront leur valeur initiale. } void retg2(graphe2 g) // change le sens du graphe : l'arc i-->j devient l'arc j-->i { int k; for(k=0;kj devient l'arc j-->i { graphe3 h; sommet i; liste l; for(i=0;is; // représente un arc de i vers j dans le graphe h. l=p->suite; // On l'enlève de la liste l des successeurs de i dans h. p->s=i; // On l'utilise pour représenter que i est un successeur de j dans g. (la nouvelle extrémité est i) p->suite=g[j], g[j]=p; // On insère le chaînon p en tête de la liste g[j] des arcs partant du sommet j dans le graphe g. } } // // Parcours itératifs de graphe pour la représentation graphe3 // bfs : en largeur d'abord (Breadth First Search) avec une file d'attente // dfs et dfspile : en profondeur d'abord (Depth First Search) avec et sans pile // void bfs(graphe3 g, sommet depart, int dist[n], sommet pere[n]) { sommet file[n], y; int debf=0, finf=0; // La file d'attente est initialement vide. liste l; for(y=0;ysuite) // pour chacun des arcs partant de x if(pere[y=l->s]==n) // qui mène à un sommet y non encore visité, { pere[y]=x; // On note qu'il est visité en notant son père dist[y]=dist[x]+1; // et sa distance au sommet de départ. file[finf++]=y; // On le met dans la file d'attente } } } void dfspile(graphe3 g, sommet depart, int dist[n], sommet pere[n]) { sommet pile[n], y; graphe3 h; int hauteur=0; // La pile est initialement vide. for(y=0;ysuite; // on va utiliser son premier élément, qu'on enlève donc de la liste pile[hauteur++]=x; // On remet x dans la pile if(pere[y=l->s]==n) // Si l'arc l mène à un sommet y non encore visité, { pere[y]=x; // On note qu'il est visité en notant son père dist[y]=dist[x]+1; // et sa distance au sommet de départ (dans l'arbre de parcours) pile[hauteur++]=y; // et on le met dans la pile } } } } void dfs(graphe3 g, sommet x, int dist[n], sommet pere[n]) { sommet y; graphe3 h; for(y=0;ysuite; // on va utiliser son premier élément, qu'on enlève donc de la liste. if(pere[y=l->s]==n) // Si l'arc l mène à un sommet y non encore visité, { pere[y]=x; // On note qu'il est visité en notant son père dist[y]=dist[x]+1; // et sa distance au sommet de départ (dans l'arbre de parcours) x=y; // et on avance sur ce sommet. } } else // Quand on a regardé tous les arcs partant de x, if(pere[x]==x) break; // si de plus x est le sommet de départ, alors on a fini, else x=pere[x]; // sinon on recule. } } // // recherche d'un cycle dans un graphe représenté par graphe2 // typedef enum{libre, ouvert, ferme} statut[n]; // Chaque sommet peut être libre, ouvert ou fermé int arr(graphe2 g, sommet pere[n]) // Rend un arc arrière dans la forêt correspondant à pere. { tetesuite tete; statut stat; int arr=n, *suite=tete+n; // Rend n s'il n'y a pas de cycle void parcours(sommet s) // Procédure récursive, s est un sommet libre { sommet t; // t est un des sommets successeurs de s int k; // k est un des arcs partant du sommet s stat[s]=ouvert; // s sera ouvert jusqu'à la fin de l'exécution de cette procédure for(k=tete[s];k>=0;k=suite[k]) // Pour chaque arc k partant du sommet s switch(stat[t=g[k].ext]) // et arrivant sur le sommet t, { case libre : pere[t]=s; parcours(t); break; // si t est libre, on va le visiter ( en mettant l'arc s-->t dans l'arbre de parcours) case ouvert: arr=k; // si t est ouvert, on a trouvé un arc arrière k : s-->t default: ; } stat[s]=ferme; // On a exploré s et tous ses successeurs } sommet s; g2ts(g,tete); // On construit les listes d'adjacence, à partir de la liste de tous les arcs. for(s=0;s=0;k=suite[k]) if(!cfc[t=g2[k].ext]) parcours1(t); finvisite[nbfin++]=s; } void parcours2(sommet s) { int k; sommet t; cfc[s]=nbcfc; // on note que s a déjà été visité for(k=tete[s];k>=0;k=suite[k]) if(cfc[t=g2[k].ext]<0) parcours2(t); } int i; g2ts(g2,tete); // chaînage des arcs sortant de chacun des sommets for(i=0;it.nn) return; if(jjnn--); descend(*t,1); return t->t[t->nn+1]; } void dijkstra(graphe2 g2, int poids[n], sommet dep, int dist[n]) { int tete[n+a], *suite=tete+n, pos[n], tt[n+1], i, k; tas t={n,tt,pos,dist}; g2ts(g2,tete); for(i=0;i=0;k=suite[k]) { sommet j=g2[k].ext; int d=dist[i]+poids[k]; if(d i et i --> 3i+1\n"); for(i=0;j=i+i ,j 3i+1 et i --> 5i+1 et 2i --> i de poids respectifs 2, 11 et 1\n"); for (i=0;3*i+1< n;i++) g2[k].ori=i, g2[k].ext=3*i+1, poids[k++]=2; for (i=0;5*i+1< n;i++) g2[k].ori=i, g2[k].ext=5*i+1, poids[k++]=11; for (i=0;2*i < n;i++) g2[k].ori=2*i, g2[k].ext=i, poids[k++]=1; printf("n=%d k=%d a=%d\n",n,k,a); if(k!=a) exit(1); } int main() { int i, ng; graphe2 g2={{0,1},{1,2},{2,3},{0,3},{1,0},{2,1},{1,3},{2,0}}, h2, k2; int poids[a]={5 , 10 , 4 , 8 , 1 , 6 , 1 , 3 }, dist[n], cfc[n]; graphe1 g1, h1; graphe3 g3, h3; void (*tfs[])(graphe3 g,sommet depart, int dist[n], sommet pere[n])={bfs,dfs,dfspile}; for(i=8;i%d(%d) ",pere[i],i,dist[i]); printf("\n"); } if(n<10000) { sommet pere[n]; int k=arr(g2,pere); if(k==n) printf("pas de cycle\n"); else affcycle(g2,pere,k); } retg2(g2); dijkstra(g2,poids,arrivee,dist); retg2(g2); for(i=0;i=0;k= dist[g2[k].ext]+poids[k]==dist[s] ? printf(" %d(%d)",s,dist[s]), tete[s=g2[k].ext] : suite[k]) ; printf(" %d(%d)\n",s,dist[s]); } return 0; }