Devoir informatique pour l’unité d’enseignement : Traité par : GUNES Aysel (Numéro étudiant : 10200610) RAMOS Pierre (Numéro étudiant: 10002201) Etudiants en Licence informatique troisième année Professeurs d’informatique en Théorie des Graphes : Cours magistraux : M LETOCART Lucas Travaux dirigés : Mme TOULOUSE Sophie (28/02/2005) Sommaire Introduction I/ Présentation des algorithmes 1) Algorithme DFS 2) Algorithme de Kosaraju-Sharir II/ Implémentation et commentaires du programme III/ Résultats théoriques 1) 2) 3) 4) Conclusion Résultat théorique sur un graphe à 4 nœuds Résultat théorique sur un graphe à 6 nœuds Résultat théorique sur un graphe à 8 nœuds Résultat théorique sur un graphe à 10 nœuds Introduction Dans le cadre de notre cursus en informatique, et plus précisément dans l’unité d’enseignement Théorie des Graphes, nous considérons le problème de la recherche des composantes fortement connexes d’un graphe orienté. Pour résoudre ce problème, nous allons utiliser l’algorithme de Kosaraju-Sharir vu en cours et en travaux dirigés. Ainsi, nous programmerons d’une part l’algorithme DFS (Deep First Search) et d’autre part, l’algorithme de Kosaraju-Sharir. Le langage utilisé sera le langage C. Aussi, nous effectuerons une analyse de complexité de l’implémentation faite. Par conséquent, dans une première partie, nous présenterons les algorithmes DFS et KosarajuSharir. Dans une deuxième partie nous donnerons l’implémentation du programme. Et, dans une dernière partie, nous donnerons les résultats théoriques obtenus sur quatre graphes différents. I/ Présentation des algorithmes Dans cette parie, nous présenterons les algorithmes DFS (Direct First Search) et Kosaraju-Sharir. 1) Algorithme DFS Détermination des composantes fortement connexes. G = (X, U) Voici ci-dessous l’algorithme DFS (Deep First Search) tel que donné en cours. Explication des notations : G : le graphe k, f : des entiers i : le sommet traité n(i) : le nombre de successeurs du sommet i d(i) : le degré du sommet i num(i) : la numérotation du sommet i prefixe(i) : la numérotation préfixe du sommet i explore(G, i) : appel à la procédure explore prenant en paramètre le graphe G et le sommet i DFS (graphe G) k 0 f 1 Pour i = 0 à n Faire n(i) d(i) Pour i = 0 à n Faire num(i) 0 Pour i = 0 à n Faire Si num(i) = 0 Alors k k +1 num(i) k prefixe(i) k explore(G, i) FinSi FinPour FinDFS Voici ci-dessous l’algorithme de la procéure explore tel que donné en cours. Explication des notations : G : le graphe i : le sommet traité j : représente le n(i)ème sommet successeur de i k, f : des entiers n(i) : le nombre de successeurs du sommet i num(i) : la numérotation du sommet i prefixe(i) : la numérotation préfixe du sommet i suffixe(i) : la numérotation suffixe du sommet i explore(G, i) : appel à la procédure explore prenant en paramètre le graphe G et le sommet i Procédure explore(graphe G, sommet i) Tantque n(i) > 0 Faire Sélectionner j le n(i)ème successeur de i n(i) n(i) – 1 Si num(i) = 0 Alors k k + 1 num(j) k prefixe(j) k explore(G, j) FinSi FinTantque suffixe(i) f f f + 1 Finexplore 2) Algorithme de Kosaraju-Sharir Détermination des composantes fortement connexes. G = (X, U) 1) 2) 3) Appilication de DFS(G) en numérotant les sommets dans l’ordre suffixe Construction du graphe G’ = (X, U’) obtenu en inversant le sens des arcs de G. Application de DFS(G’) en démarrant par le sommet de plus grand numéro suffixe et itération du processus à partir du sommet non marqué de plus grand numéro suffixe. II/ Implémentation et commentaires du programme Les commentaires sont faits avant chaque petite partie de code. /* Declaration des bibliotheques */ #include<stdio.h> #include<stdlib.h> #include<string.h> /* Definition des constantes */ #define TRUE 0 #define FALSE 1 /* Definition de structures de donnees */ /* valeur: la valeur du noeud nbPred: le nombre de predecesseurs de ce noeud nbSucc: le nombre de successeurs de ce noeud successeurs: double pointeur sur cette structure de donnees qui va representer l'ensemble des successeurs de ce noeud predecesseurs: double pointeur sur cette structure de donnees qui va representer l'ensemble des predecesseurs de ce neoud nbSuccTemp: le nombre de successeurs de ce neoud (il est defini comme temporaire dans la mesure où ce sera ce champ qui sera modifie lors du parcours DFS et non le champ nbSucc numerotation: la numerotation de ce noeud prefixe: la numerotation prefixe de ce noeud suffixe: la numerotation suffixe de ce noeud */ typedef struct NoeudGraphe_{ int valeur; int nbPred; int nbSucc; struct NoeudGraphe_** successeurs; struct NoeudGraphe_** predecesseurs; // les champs suivants ne sont utilises que dans // le cadre d'un parcours DFS int nbSuccTemp; int numerotation; int prefixe; int suffixe; }NoeudGraphe; /* noeuds: pointeur sur la structure de donnees precedente NoeudGraphe nbnoeuds: le nombre de noeuds du graphe */ typedef struct{ NoeudGraphe* noeuds; int nbNoeuds; }Graphe; /* Procedure permettant d'initialiser un nouveau noeud a partir des valeurs envoyees en parametre; les champs utilises pour le deroulement de l'algorithme DFS sont initialises a 0 */ void nouveauNoeud(int valeur,int nbPred,int nbSucc, NoeudGraphe** predecesseurs, NoeudGraphe** successeurs, int numerotation,NoeudGraphe* nouveauNoeud){ int i; nouveauNoeud->valeur=valeur; nouveauNoeud->nbPred=nbPred; nouveauNoeud->nbSucc=nbSucc; nouveauNoeud->nbSuccTemp=0; nouveauNoeud->numerotation=numerotation; nouveauNoeud->prefixe=0; nouveauNoeud->suffixe=0; nouveauNoeud->predecesseurs= (NoeudGraphe**)malloc(nbPred*sizeof(NoeudGraphe*)); nouveauNoeud->successeurs= (NoeudGraphe**)malloc(nbSucc*sizeof(NoeudGraphe*)); for(i=0;i<nbPred;i=i+1){ nouveauNoeud->predecesseurs[i]=predecesseurs[i]; } for(i=0;i<nbSucc;i=i+1){ nouveauNoeud->successeurs[i]=successeurs[i]; } } /* Procedure explore qui sera utilisee pour le deroulement de l'algorithme DFS prenant en argument un graphe, un noeud de ce graphe et deux entiers */ int explore(NoeudGraphe *i,int k,int* f){ int renvoi=1; while(i->nbSuccTemp>0){ i->nbSuccTemp=i->nbSuccTemp-1; if(i->successeurs[i->nbSuccTemp]->numerotation==0){ k=k+1; i->successeurs[i->nbSuccTemp]->numerotation=k; i->successeurs[i->nbSuccTemp]->prefixe=k; renvoi=1+explore(i->successeurs[i->nbSuccTemp],k,f); } } i->suffixe=*f; *f=(*f)+1; return(renvoi); } /* Procedure implementant l'algorithme DFS qui sera utilise pour le deroulement de l'algorithme Kosaraju-Sharir prenant en argument un pointeur sur Graphe */ int dfs(Graphe* graphe){ int i,j,k,f; int renvoi; k=0; f=1; for(i=0;i<graphe->nbNoeuds;i=i+1){ graphe->noeuds[i].nbSuccTemp=graphe->noeuds[i].nbSucc; graphe->noeuds[i].numerotation=0; } renvoi=graphe->nbNoeuds; for(j=0;j<graphe->nbNoeuds;j=j+1){ if(graphe->noeuds[j].numerotation==0){ k=k+1; graphe->noeuds[j].numerotation=k; graphe->noeuds[j].prefixe=k; renvoi=renvoi+explore(&(graphe->noeuds[j]),k,&f); } } return(renvoi); } /* procedure implementant l'algorithme de Kosaraju-Sharir prenant en argument deux pointeurs sur Graphe */ int kosarajuSharir(Graphe* graphe){ int i,j,nbSufMax,numSufMax,nbNumMax,numNumMax; int* marquage; int renvoi; //graphe2 est un Graphe temporaire permettant de faire les tris Graphe graphe2; renvoi=dfs(graphe); // On genere un 2ieme graphe, dont les noeuds sont tries // dans l'ordre de leur notation suffixe graphe2.nbNoeuds=graphe->nbNoeuds; graphe2.noeuds=(NoeudGraphe*)malloc(graphe-> nbNoeuds*sizeof(NoeudGraphe*)); marquage=(int*)malloc(graphe->nbNoeuds*sizeof(int)); for(i=0;i<graphe->nbNoeuds;i=i+1){ marquage[i]=FALSE; } for(i=0;i<graphe->nbNoeuds;i=i+1){ numSufMax=-1; for(j=0;j<graphe->nbNoeuds;j=j+1){ if(graphe->noeuds[j].suffixe>numSufMax){ if(marquage[j]==FALSE){ numSufMax=graphe->noeuds[j].suffixe; nbSufMax=j; } } } marquage[nbSufMax]=TRUE; nouveauNoeud(graphe->noeuds[nbSufMax].valeur,graphe-> noeuds[nbSufMax].nbSucc,graphe-> noeuds[nbSufMax].nbPred,graphe-> noeuds[nbSufMax].successeurs,graphe-> noeuds[nbSufMax].predecesseurs,graphe-> noeuds[nbSufMax].numerotation,&(graphe2.noeuds[i])); } renvoi=renvoi+graphe->nbNoeuds*3; for(i=0;i<graphe->nbNoeuds;i=i+1){ nouveauNoeud(graphe2.noeuds[i].valeur,graphe2.noeuds[i].nbPred, graphe2.noeuds[i].nbSucc,graphe2.noeuds[i].predecesseurs, graphe2.noeuds[i].successeurs,graphe2.noeuds[i].numerotation, &(graphe->noeuds[i])); } // On applique l'algorithme DFS au 2 ieme graphe genere renvoi=renvoi+dfs(graphe); // On trie les noeuds du 2 ieme graphe selon leur notation // prefixe, ce qui les classe selon leur composante connexe for(i=0;i<graphe->nbNoeuds;i=i+1){ marquage[i]=FALSE; } nbNumMax=0; for(i=0;i<graphe->nbNoeuds;i=i+1){ numNumMax=graphe->nbNoeuds+1; for(j=0;j<graphe->nbNoeuds;j=j+1){ if(graphe->noeuds[j].numerotation<numNumMax){ if(marquage[j]==FALSE){ numNumMax=graphe->noeuds[j].numerotation; nbNumMax=j; } } } marquage[nbNumMax]=TRUE; nouveauNoeud(graphe->noeuds[nbNumMax].valeur,graphe-> noeuds[nbNumMax].nbPred,graphe-> noeuds[nbNumMax].nbSucc,graphe-> noeuds[nbNumMax].predecesseurs,graphe-> noeuds[nbNumMax].successeurs,graphe-> noeuds[nbNumMax].numerotation,&(graphe2.noeuds[i])); } for(i=0;i<graphe->nbNoeuds;i=i+1){ nouveauNoeud(graphe2.noeuds[i].valeur,graphe2.noeuds[i].nbPred, graphe2.noeuds[i].nbSucc,graphe2.noeuds[i].predecesseurs, graphe2.noeuds[i].successeurs,graphe2.noeuds[i].numerotation, &(graphe->noeuds[i])); } renvoi=renvoi+graphe2.nbNoeuds*3; return(renvoi); } /* Procedure permettant d'initialiser un graphe a 10 noeuds, ce graphe forme un circuit, il sera appele lors des tests */ void graphe10noeuds(Graphe* graphe) { int i; NoeudGraphe** tabPred; NoeudGraphe** tabSucc; graphe->nbNoeuds=10; graphe->noeuds=(NoeudGraphe*)malloc(graphe-> nbNoeuds*sizeof(NoeudGraphe)); for(i=1;i<11;i=i+1){ tabPred=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[((i-1)%10)]; tabSucc[0]=&graphe->noeuds[((i+1)%10)]; nouveauNoeud(i%10,1,1,tabPred,tabSucc,0,&(graphe-> noeuds[i%10])); free(tabPred); free(tabSucc); } } /* Procedure permettant d'initialiser un graphe a 6 noeuds */ void graphe4noeuds(Graphe* graphe) { NoeudGraphe** tabPred; NoeudGraphe** tabSucc; graphe->nbNoeuds=4; graphe->noeuds=(NoeudGraphe*)malloc(graphe-> nbNoeuds*sizeof(NoeudGraphe)); // Noeud: 1 tabPred=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[3]; tabSucc[0]=&graphe->noeuds[1]; tabSucc[1]=&graphe->noeuds[2]; nouveauNoeud(0,1,2,tabPred,tabSucc,0,&graphe->noeuds[0]); free(tabPred); free(tabSucc); // Noeud: 2 tabPred=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[0]; tabSucc[0]=&graphe->noeuds[3]; nouveauNoeud(1,1,1,tabPred,tabSucc,0,&graphe->noeuds[1]); free(tabPred); free(tabSucc); // Noeud: 3 tabPred=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[0]; tabSucc[0]=&graphe->noeuds[3]; nouveauNoeud(2,1,1,tabPred,tabSucc,0,&graphe->noeuds[2]); free(tabPred); free(tabSucc); // Noeud: 4 tabPred=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[1]; tabPred[1]=&graphe->noeuds[2]; tabSucc[0]=&graphe->noeuds[0]; nouveauNoeud(3,2,1,tabPred,tabSucc,0,&graphe->noeuds[3]); free(tabPred); free(tabSucc); } /* Procedure permettant d'initialiser un graphe a 6 noeuds */ void graphe6noeuds(Graphe* graphe) { NoeudGraphe** tabPred; NoeudGraphe** tabSucc; graphe->nbNoeuds=6; graphe->noeuds=(NoeudGraphe*)malloc(graphe-> nbNoeuds*sizeof(NoeudGraphe)); // Noeud: 1 tabPred=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[2]; tabSucc[0]=&graphe->noeuds[1]; nouveauNoeud(0,1,1,tabPred,tabSucc,0,&graphe->noeuds[0]); free(tabPred); free(tabSucc); // Noeud: 2 tabPred=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[0]; tabPred[1]=&graphe->noeuds[5]; tabSucc[0]=&graphe->noeuds[2]; nouveauNoeud(1,2,1,tabPred,tabSucc,0,&graphe->noeuds[1]); free(tabPred); free(tabSucc); // Noeud: 3 tabPred=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[1]; tabPred[1]=&graphe->noeuds[4]; tabSucc[0]=&graphe->noeuds[0]; tabSucc[1]=&graphe->noeuds[3]; nouveauNoeud(2,2,2,tabPred,tabSucc,0,&graphe->noeuds[2]); free(tabPred); free(tabSucc); // Noeud: 4 tabPred=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[2]; tabPred[1]=&graphe->noeuds[4]; tabSucc[0]=&graphe->noeuds[5]; nouveauNoeud(3,2,1,tabPred,tabSucc,0,&graphe->noeuds[3]); free(tabPred); free(tabSucc); // Noeud: 5 tabPred=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[5]; tabSucc[0]=&graphe->noeuds[2]; tabSucc[1]=&graphe->noeuds[3]; nouveauNoeud(4,1,2,tabPred,tabSucc,0,&graphe->noeuds[4]); free(tabPred); free(tabSucc); // Noeud: 6 tabPred=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[3]; tabSucc[0]=&graphe->noeuds[1]; tabSucc[1]=&graphe->noeuds[4]; nouveauNoeud(5,1,2,tabPred,tabSucc,0,&graphe->noeuds[5]); free(tabPred); free(tabSucc); } /* Procedure permettant d'initialiser un graphe a 8 noeuds */ void graphe8noeuds(Graphe* graphe) { NoeudGraphe** tabPred; NoeudGraphe** tabSucc; graphe->nbNoeuds=8; graphe->noeuds=(NoeudGraphe*)malloc(graphe-> nbNoeuds*sizeof(NoeudGraphe)); // Noeud: 1 tabPred=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[7]; tabSucc[0]=&graphe->noeuds[3]; nouveauNoeud(0,1,1,tabPred,tabSucc,0,&graphe->noeuds[0]); free(tabPred); free(tabSucc); // Noeud: 2 tabPred=(NoeudGraphe**)malloc(1*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[3]; tabSucc[0]=&graphe->noeuds[2]; tabSucc[1]=&graphe->noeuds[4]; nouveauNoeud(1,1,2,tabPred,tabSucc,0,&graphe->noeuds[1]); free(tabPred); free(tabSucc); // Noeud: 3 tabPred=(NoeudGraphe**)malloc(3*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[1]; tabPred[1]=&graphe->noeuds[4]; tabPred[2]=&graphe->noeuds[7]; tabSucc[0]=&graphe->noeuds[3]; tabSucc[1]=&graphe->noeuds[7]; nouveauNoeud(2,3,2,tabPred,tabSucc,0,&graphe->noeuds[2]); free(tabPred); free(tabSucc); // Noeud: 4 tabPred=(NoeudGraphe**)malloc(3*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[0]; tabPred[1]=&graphe->noeuds[2]; tabPred[2]=&graphe->noeuds[3]; tabSucc[0]=&graphe->noeuds[5]; tabSucc[1]=&graphe->noeuds[1]; nouveauNoeud(3,3,2,tabPred,tabSucc,0,&graphe->noeuds[3]); free(tabPred); free(tabSucc); // Noeud: 5 tabPred=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[1]; tabPred[1]=&graphe->noeuds[5]; tabSucc[0]=&graphe->noeuds[2]; tabSucc[1]=&graphe->noeuds[6]; nouveauNoeud(4,2,2,tabPred,tabSucc,0,&graphe->noeuds[4]); free(tabPred); free(tabSucc); // Noeud: 6 tabPred=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[3]; tabPred[1]=&graphe->noeuds[6]; tabSucc[0]=&graphe->noeuds[4]; tabSucc[1]=&graphe->noeuds[7]; nouveauNoeud(5,2,2,tabPred,tabSucc,0,&graphe->noeuds[5]); free(tabPred); free(tabSucc); // Noeud: 7 tabPred=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[4]; tabPred[1]=&graphe->noeuds[7]; tabSucc[0]=&graphe->noeuds[3]; tabSucc[1]=&graphe->noeuds[5]; nouveauNoeud(6,2,2,tabPred,tabSucc,0,&graphe->noeuds[6]); free(tabPred); free(tabSucc); // Noeud: 8 tabPred=(NoeudGraphe**)malloc(2*sizeof(NoeudGraphe*)); tabSucc=(NoeudGraphe**)malloc(3*sizeof(NoeudGraphe*)); tabPred[0]=&graphe->noeuds[3]; tabPred[1]=&graphe->noeuds[6]; tabSucc[0]=&graphe->noeuds[2]; tabSucc[1]=&graphe->noeuds[5]; tabSucc[2]=&graphe->noeuds[2]; nouveauNoeud(7,2,3,tabPred,tabSucc,0,&graphe->noeuds[7]); free(tabPred); free(tabSucc); } /* Fonction principale */ int main(void){ Graphe graphe; int i,complexite1,complexite2,reponse; do{ printf("Entrez le nombre de noeuds du graphe que vous desirez (choix entre 4,6,8 et 10 noeuds)\n"); scanf("%d",&reponse); }while((reponse!=4)&&(reponse!=6)&&(reponse!=8)&&(reponse!=10)); switch(reponse){ case 4:{ graphe4noeuds(&graphe); break; } case 6:{ graphe6noeuds(&graphe); break; } case 8:{ graphe8noeuds(&graphe); break; } case 10:{ graphe10noeuds(&graphe); break; } } complexite2=dfs(&graphe); printf("\t\t ----------\n"); printf("\t\t| Graphe 1 |\n"); printf("\t\t ----------\n"); printf("\nVal noeud Nbr pred Nbr succ\n"); printf("---------------------------------\n"); for(i=0;i<graphe.nbNoeuds;i=i+1){ printf(" %d %d %d\n", graphe.noeuds[i].valeur,graphe.noeuds[i].nbPred, graphe.noeuds[i].nbSucc); } printf("\nNb SuccTemp Numerotation Num prefixe Num suffixe\n"); printf("------------------------------------------------------\n"); for(i=0;i<graphe.nbNoeuds;i=i+1){ printf(" %d %d %d %d\n", graphe.noeuds[i].nbSuccTemp,graphe.noeuds[i].numerotation, graphe.noeuds[i].prefixe,graphe.noeuds[i].suffixe); } switch(reponse){ case 4:{ graphe4noeuds(&graphe); break; } case 6:{ graphe6noeuds(&graphe); break; } case 8:{ graphe8noeuds(&graphe); break; } case 10:{ graphe10noeuds(&graphe); break; } } complexite1=kosarajuSharir(&graphe); printf("\n\n\n\t\t ----------\n"); printf("\t\t| Graphe 2 |\n"); printf("\t\t ----------\n"); printf("\nVal noeud Nbr pred Nbr succ\n"); printf("-------------------------------\n"); for(i=0;i<graphe.nbNoeuds;i=i+1){ printf(" %d %d %d\n", graphe.noeuds[i].valeur,graphe.noeuds[i].nbPred, graphe.noeuds[i].nbSucc); } printf("\nNb SuccTemp Numerotation Num prefixe Num suffixe\n"); printf("------------------------------------------------------\n"); for(i=0;i<graphe.nbNoeuds;i=i+1){ printf(" %d %d %d %d\n", graphe.noeuds[i].nbSuccTemp,graphe.noeuds[i].numerotation, graphe.noeuds[i].prefixe,graphe.noeuds[i].suffixe); } printf("\nLa complexite de kosaraju sharir est : %d\n", complexite1); printf("\nLa complexite de l'algorithme DFS est : %d\n", complexite2); free(graphe.noeuds); } III/ Résultats théoriques Nous avons généré quatre graphes avec un nombre de noeuds différents à chaque fois pour tester si notre programme fonctionne bien que nous ayons des problèmes au niveau de l’exécution de l’algorithme de Kosaraju-Sharir. 1) Résultat théorique sur un graphe à 4 nœuds Détermination des composantes fortement connexes. G = (X, U) 0 1 3 2 Application de l’algorithme DFS sur le graphe G selon la manière vue en travaux dirigés : (Remarque : x représente le nœud traité et (x), l’ensemble des successeurs de x.) Préfixe Suffixe x (x) 1 2 3 4 4 3 2 1 0 1 2 3 1 2 1, 3 0, 1 Graphe réduit résultant du DFS sur G : 0 1 2 3 Soit le graphe G’ = (X, U’) obtenu en inversant les arcs du graphe G : 0 1 3 2 Application de l’algorithme DFS sur le graphe G’ en commençant par le sommet de plus grand numéro suffixe et en itérant ce processus à partir du sommet non marqué de plus grand numéro suffixe : Préfixe Suffixe x (x) 1 2 3 4 4 3 2 1 0 2 1 3 2, 3 1 0, 3 2 Graphe réduit résultant du DFS sur G’ : 0 2 1 3 2) Résultat théorique sur un graphe à 6 nœuds Détermination des composantes fortement connexes. G = (X, U) 0 1 3 2 4 5 Application de l’algorithme DFS sur le graphe G selon la manière vue en travaux dirigés : (Remarque : x représente le nœud traité et (x), l’ensemble des successeurs de x.) Préfixe Suffixe x (x) 1 2 3 4 5 6 6 5 4 3 2 1 0 1 2 3 5 4 1 2 0, 3 5 4 3 Graphe réduit résultant du DFS sur G : 0 1 2 3 4 5 Soit le graphe G’ = (X, U’) obtenu en inversant les arcs du graphe G : 0 1 3 2 4 5 Application de l’algorithme DFS sur le graphe G’ en commençant par le sommet de plus grand numéro suffixe et en itérant ce processus à partir du sommet non marqué de plus grand numéro suffixe : Préfixe Suffixe x (x) 1 2 3 4 5 6 6 5 4 3 2 1 0 2 1 5 3 4 2 1, 3, 4 0, 5 3 2, 4 5 Graphe réduit résultant du DFS sur G’ : 0 2 1 5 3 4 3) Résultat théorique sur un graphe à 8 nœuds Détermination des composantes fortement connexes. G = (X, U) 1 4 2 0 3 5 7 6 Application de l’algorithme DFS sur le graphe G selon la manière vue en travaux dirigés : (Remarque : x représente le nœud traité et (x), l’ensemble des successeurs de x.) Préfixe Suffixe x (x) 1 2 3 4 5 6 7 8 8 7 6 5 4 3 2 1 0 3 1 4 6 5 7 2 3 5, 1 2, 4 2, 6 3, 5 7 0, 6, 2 3, 7 Graphe réduit résultant du DFS sur G : 0 3 1 4 6 5 7 2 Soit le graphe G’ = (X, U’) obtenu en inversant les arcs du graphe G : 1 4 2 0 3 5 7 6 Application de l’algorithme DFS sur le graphe G’ en commençant par le sommet de plus grand numéro suffixe et en itérant ce processus à partir du sommet non marqué de plus grand numéro suffixe : Préfixe Suffixe x (x) 1 8 0 7 2 3 4 5 6 7 8 7 5 4 3 2 1 6 7 5 6 4 1 3 2 2, 5 0, 6 4, 7 5, 1 3 0, 6, 1, 3, 4, 7 Graphe réduit résultant du DFS sur G’ : 0 7 5 6 4 1 3 2 4) Résultat théorique sur un graphe à 10 nœuds Détermination des composantes fortement connexes. G = (X, U) 2 3 4 1 5 0 6 9 8 7 Application de l’algorithme DFS sur le graphe G selon la manière vue en travaux dirigés : (Remarque : x représente le nœud traité et (x), l’ensemble des successeurs de x.) Préfixe Suffixe x (x) 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 0 1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9 0 Graphe réduit résultant du DFS sur G : 0 1 2 3 4 5 6 7 Soit le graphe G’ = (X, U’) obtenu en inversant les arcs du graphe G : 8 9 2 3 4 1 5 0 6 9 8 7 Application de l’algorithme DFS sur le graphe G’ en commençant par le sommet de plus grand numéro suffixe et en itérant ce processus à partir du sommet non marqué de plus grand numéro suffixe : Préfixe Suffixe x (x) 1 2 3 4 5 6 7 8 9 10 10 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 9 8 7 6 5 4 3 2 1 0 Graphe réduit résultant du DFS sur G’ : 0 9 8 7 6 5 4 3 2 1 Conclusion En définitif, le fait de programmer un algorithme de recherche des composantes fortement connexes comme celui de Kosaraju-Sharir nous a permis une meilleure compréhension du fonctionnement de l’algorithme en question. Cependant, nous avons été confrontés à quelques difficultés. En effet dans l’implémentation de l’algorithme de Kosaraju-Sharir nous avons des problèmes de pointeurs. Effectivement, le graphe de quatre nœuds fonctionne comme il se doit mais les autres génèrent des erreurs d’exécution. Nous espérons tout de même que la théorie de notre programme soit conforme à vos attentes. Nous tenons à remercier tout particulièrement nos professeurs d’informatique Monsieur LETOCART Lucas et Madame TOULOUSE Sophie.